<!doctype html><html lang="zh"><head><meta charset="utf-8"><meta name="generator" content="Hexo 4.2.0"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta><meta name="keywords" content="null"><meta name="description" content="技术与生活缺一不可✔"><meta name="author" content="Wxperia 🛠"><title>谢子乾</title><meta description="技术与生活缺一不可✔"><meta property="og:type" content="website"><meta property="og:title" content="Wxperia"><meta property="og:url" content="https://wxperia.github.io/"><meta property="og:site_name" content="子乾的个人博客"><meta property="og:description" content="技术与生活缺一不可✔"><meta property="og:locale" content="zh_CN"><meta property="article:author" content="Wxperia 🛠"><meta property="twitter:card" content="summary"><meta property="twitter:image" content="https://wxperia.github.io/img/avatar.png"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"https://Wxperia.github.io/"},"headline":"謝子乾 🐱‍🏍","image":["https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png"],"author":{"@type":"Person","name":"Wxperia 🛠"},"description":"技术与生活缺一不可✔"}</script><link rel="alternative" href="/atom.xml" title="谢子乾" type="application/atom+xml"><link rel="icon" href="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png"><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/font-awesome/5.12.0/css/all.min.css"><link rel="stylesheet" href="https://fonts.loli.net/css?family=Ubuntu:400,600|Source+Code+Pro|Monda:300,300italic,400,400italic,700,700italic|Roboto Slab:300,300italic,400,400italic,700,700italic|Microsoft YaHei:300,300italic,400,400italic,700,700italic|PT Mono:300,300italic,400,400italic,700,700italic&amp;amp;subset=latin,latin-ext|Inconsolata|Itim|Lobster.css"><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css"><style>body>.footer,body>.navbar,body>.section{opacity:0}</style><script src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" defer></script><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/lightgallery/1.6.12/css/lightgallery.min.css"><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/justifiedGallery/3.7.0/css/justifiedGallery.min.css"><script src="https://cdnjs.loli.net/ajax/libs/pace/1.0.2/pace.min.js"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//css/style.min.css"><link rel="stylesheet" href="/css/e-style.css"><script src="https://cdnjs.loli.net/ajax/libs/jquery/3.3.1/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/globalUtils.min.js"></script></head><body class="is-3-column has-navbar-fixed-top"><nav class="navbar navbar-main is-fixed-top"><div class="container"><div class="navbar-brand justify-content-center"><a class="navbar-item navbar-logo" href="/"><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png" alt="谢子乾" height="28"></a></div><div class="navbar-menu"><div class="navbar-start"><a class="navbar-item is-active" href="/">首页</a><a class="navbar-item" href="/archives">归档</a><a class="navbar-item" href="/categories">分类</a><a class="navbar-item" href="/tags">标签</a><a class="navbar-item" href="/album">相册</a></div><div class="navbar-end"><a class="navbar-item" target="_blank" rel="noopener" title="Download on GitHub" href="https://github.com/removeif"><i class="fab fa-github"></i></a><a class="navbar-item search" title="搜索" href="javascript:;"><i class="fas fa-search"></i></a><a class="navbar-item" id="night-nav" title="Night Mode" href="javascript:;"><i class="fas fa-moon" id="night-icon"></i></a></div></div></div></nav><script type="text/javascript" src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/theme-setting.min.js"></script><section class="section"><div class="container"><div class="columns"><div class="column order-2 column-main is-8-tablet is-8-desktop is-6-widescreen"><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-12-29  <a class="commentCountImg" href="/2020/12/29/%E3%80%90vue%E3%80%91%E8%A7%A3%E8%80%A6%E6%A8%A1%E5%9D%97%E4%B9%8B%E9%97%B4%E7%9A%84%E8%AF%AD%E8%A8%80%E6%96%87%E4%BB%B6/#comment-container"><span class="display-none-class">1d3cbe636f13a38d612b76fd68401c9b</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="1d3cbe636f13a38d612b76fd68401c9b">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>5 分钟  <i class="fas fa-pencil-alt"> </i>0.8 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/12/29/%E3%80%90vue%E3%80%91%E8%A7%A3%E8%80%A6%E6%A8%A1%E5%9D%97%E4%B9%8B%E9%97%B4%E7%9A%84%E8%AF%AD%E8%A8%80%E6%96%87%E4%BB%B6/">【vue】解耦模块之间的语言文件</a></h1><div class="content"><h1 id="引入vue-i18n"><a href="#引入vue-i18n" class="headerlink" title="引入vue-i18n"></a>引入vue-i18n</h1><p>项目UI用的是element, 所以需要连element一起把多语言给做了</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> VueI18n <span class="keyword">from</span> <span class="string">'vue-i18n'</span></span><br><span class="line"><span class="keyword">import</span> messages <span class="keyword">from</span> <span class="string">'./langs'</span></span><br><span class="line"><span class="keyword">import</span> ElementUI <span class="keyword">from</span> <span class="string">'element-ui'</span></span><br><span class="line"><span class="keyword">import</span> enlocale <span class="keyword">from</span> <span class="string">'element-ui/lib/locale/lang/en'</span></span><br><span class="line"><span class="keyword">import</span> cnlocale <span class="keyword">from</span> <span class="string">'element-ui/lib/locale/lang/zh-CN'</span></span><br><span class="line"><span class="keyword">import</span> mergeWith <span class="keyword">from</span> <span class="string">'lodash/mergeWith'</span></span><br><span class="line">Vue.use(VueI18n)</span><br><span class="line">Vue.use(ElementUI, &#123;</span><br><span class="line">  i18n: <span class="function">(<span class="params">key, value</span>) =&gt;</span> i18n.t(key, value)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 合并element和自己设置的公共多语言文件</span></span><br><span class="line"><span class="keyword">let</span> merageEn = mergeWith(messages.en, enlocale)</span><br><span class="line"><span class="keyword">let</span> merageCn = mergeWith(messages.cn, cnlocale)</span><br><span class="line"><span class="keyword">const</span> i18n = <span class="keyword">new</span> VueI18n(&#123;</span><br><span class="line">  locale: <span class="string">'cn'</span>,</span><br><span class="line">  messages: &#123;</span><br><span class="line">    cn: merageCn,</span><br><span class="line">    en: merageEn</span><br><span class="line">  &#125;,</span><br><span class="line">  silentTranslationWarn: <span class="literal">true</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 扩展i18n动态修改语言包的方法</span></span><br><span class="line"><span class="comment">// 添加新的国际化i18nObj</span></span><br><span class="line">i18n.addNewLang = <span class="function"><span class="keyword">function</span> (<span class="params">lang</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 合并之前的旧的国际化类</span></span><br><span class="line">  merageEn = mergeWith(merageEn, lang.en)</span><br><span class="line">  merageCn = mergeWith(merageCn, lang.cn)</span><br><span class="line">  <span class="comment">// i18n对象热更新</span></span><br><span class="line">  i18n.setLocaleMessage(<span class="string">'en'</span>, merageEn)</span><br><span class="line">  i18n.setLocaleMessage(<span class="string">'cn'</span>, merageCn)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> i18n</span><br></pre></td></tr></table></figure><h2 id="在main-js文件中引入"><a href="#在main-js文件中引入" class="headerlink" title="在main.js文件中引入"></a>在main.js文件中引入</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> i18n <span class="keyword">from</span> <span class="string">'@/common/i18n/i18n.js'</span></span><br><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">    router,</span><br><span class="line">    store,</span><br><span class="line">    i18n,</span><br><span class="line">    render: <span class="function"><span class="params">h</span> =&gt;</span> h(App)</span><br><span class="line">  &#125;).$mount(<span class="string">'#app'</span>)</span><br></pre></td></tr></table></figure><h2 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h2><p>i18n 对象结构</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="comment">// 英文相关字段</span></span><br><span class="line">  en: &#123;  <span class="comment">// 'en' Locale</span></span><br><span class="line">    key1: <span class="string">"this is message1"</span>, <span class="comment">// 基本的</span></span><br><span class="line">    nested: &#123; <span class="comment">// 嵌套</span></span><br><span class="line">      message1: <span class="string">"this is nested message1"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    errors: [ <span class="comment">// 数组</span></span><br><span class="line">      <span class="string">"this is 0 error code message"</span>,</span><br><span class="line">      &#123;  <span class="comment">// 数组嵌套对象</span></span><br><span class="line">        <span class="string">"internal1"</span>: <span class="string">"this is internal 1 error message"</span></span><br><span class="line">      &#125;,</span><br><span class="line">      [  <span class="comment">// 数组嵌套数组</span></span><br><span class="line">        <span class="string">"this is nested array error 1"</span></span><br><span class="line">      ]</span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 中文相关字段</span></span><br><span class="line">  cn: &#123; <span class="comment">// 'cn' Locale</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">    key1: <span class="string">"这是一条message1"</span>, <span class="comment">// 基本的</span></span><br><span class="line">    nested: &#123; <span class="comment">// 嵌套</span></span><br><span class="line">      message1: <span class="string">"这是嵌套的message1"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    errors: [ <span class="comment">// 数组</span></span><br><span class="line">      <span class="string">"这是0错误代码消息"</span>,</span><br><span class="line">      &#123;  <span class="comment">// 数组嵌套对象</span></span><br><span class="line">        <span class="string">"internal1"</span>: <span class="string">"这是内部1错误消息"</span></span><br><span class="line">      &#125;,</span><br><span class="line">      [  <span class="comment">// 数组嵌套数组</span></span><br><span class="line">        <span class="string">"这是嵌套数组错误1"</span></span><br><span class="line">      ]</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在 vue 单文件中使用</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 基本的 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;&#123; $t('key1') &#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 嵌套 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;&#123; $t('nested.message1') &#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 数组 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;&#123; $t('errors[0]') &#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 数组嵌套对象 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;&#123; $t('errors[1].internal1') &#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 数组嵌套数组 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;&#123; $t('errors[2][0]') &#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- 输出以下内容 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 基本的 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>this is message1<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 嵌套 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>this is nested message1<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 数组 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>this is 0 error code message<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 数组嵌套对象 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>this is internal 1 error message<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 数组嵌套数组 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span>this is nested array error 1<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>在 vue 单文件 js 代码中使用</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> lang = &#123;</span><br><span class="line">	en: &#123;</span><br><span class="line">		<span class="comment">// 'en' Locale</span></span><br><span class="line">		<span class="comment">// 这个变量需要用自己的模块名，防止与其他模块冲突，如果有冲突addNewLang会抛出错误</span></span><br><span class="line">		modelName: &#123;</span><br><span class="line">			<span class="comment">//... 模块需要用到的变量名</span></span><br><span class="line">		&#125;,</span><br><span class="line">	&#125;,</span><br><span class="line">	<span class="comment">// 中文相关字段规则与上面的一致</span></span><br><span class="line">	cn: &#123;</span><br><span class="line">		<span class="comment">// 'cn' Locale</span></span><br><span class="line">		<span class="comment">// ...</span></span><br><span class="line">		key1: <span class="string">'这是一条message1'</span>, <span class="comment">// 基本的</span></span><br><span class="line">		nested: &#123;</span><br><span class="line">			<span class="comment">// 嵌套</span></span><br><span class="line">			message1: <span class="string">'这是嵌套的message1'</span>,</span><br><span class="line">		&#125;,</span><br><span class="line">		errors: [</span><br><span class="line">			<span class="comment">// 数组</span></span><br><span class="line">			<span class="string">'这是0错误代码消息'</span>,</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="comment">// 数组嵌套对象</span></span><br><span class="line">				internal1: <span class="string">'这是内部1错误消息'</span>,</span><br><span class="line">			&#125;,</span><br><span class="line">			[</span><br><span class="line">				<span class="comment">// 数组嵌套数组</span></span><br><span class="line">				<span class="string">'这是嵌套数组错误1'</span>,</span><br><span class="line">			],</span><br><span class="line">		],</span><br><span class="line">	&#125;,</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">	created() &#123;</span><br><span class="line">		<span class="comment">// 加载对应的文件</span></span><br><span class="line">		<span class="keyword">this</span>.$i18n.addNewLang(lang)</span><br><span class="line">	&#125;,</span><br><span class="line">	data() &#123;</span><br><span class="line">		key1: <span class="keyword">this</span>.$t(<span class="string">'message.key1'</span>)</span><br><span class="line">	&#125;,</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 输出：</span></span><br><span class="line"><span class="comment">//cn: 这是一条message1</span></span><br><span class="line"><span class="comment">//en: this is message1</span></span><br></pre></td></tr></table></figure><p>在普通 js 文件中使用</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 引入 i18n模块</span></span><br><span class="line"><span class="keyword">import</span> i18n <span class="keyword">from</span> <span class="string">'@/common/i18n/i18n.js'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建i18n规则</span></span><br><span class="line"><span class="keyword">const</span> lang = &#123;</span><br><span class="line">	en: &#123;</span><br><span class="line">		<span class="comment">// 'en' Locale</span></span><br><span class="line">		<span class="comment">// 这个变量需要用自己的模块名，防止与其他模块冲突，如果有冲突addNewLang会抛出错误</span></span><br><span class="line">		modelName: &#123;</span><br><span class="line">			<span class="comment">//... 模块需要用到的变量名</span></span><br><span class="line">		&#125;,</span><br><span class="line">	&#125;,</span><br><span class="line">	<span class="comment">// 中文相关字段规则与上面的一致</span></span><br><span class="line">	cn: &#123;</span><br><span class="line">		<span class="comment">// 'cn' Locale</span></span><br><span class="line">		<span class="comment">// ...</span></span><br><span class="line">		key1: <span class="string">'这是一条message1'</span>, <span class="comment">// 基本的</span></span><br><span class="line">		nested: &#123;</span><br><span class="line">			<span class="comment">// 嵌套</span></span><br><span class="line">			message1: <span class="string">'这是嵌套的message1'</span>,</span><br><span class="line">		&#125;,</span><br><span class="line">		errors: [</span><br><span class="line">			<span class="comment">// 数组</span></span><br><span class="line">			<span class="string">'这是0错误代码消息'</span>,</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="comment">// 数组嵌套对象</span></span><br><span class="line">				internal1: <span class="string">'这是内部1错误消息'</span>,</span><br><span class="line">			&#125;,</span><br><span class="line">			[</span><br><span class="line">				<span class="comment">// 数组嵌套数组</span></span><br><span class="line">				<span class="string">'这是嵌套数组错误1'</span>,</span><br><span class="line">			],</span><br><span class="line">		],</span><br><span class="line">	&#125;,</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 加载此规则</span></span><br><span class="line">i18n.addNewLang(lang)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> test = i18n.t(<span class="string">'key1'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// console.log(test)</span></span><br><span class="line"><span class="comment">// 输出：</span></span><br><span class="line"><span class="comment">// cn: "这是一条message1"</span></span><br><span class="line"><span class="comment">// en: "this is message1"</span></span><br></pre></td></tr></table></figure></div><div class="index-category-tag">  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-12-28  <a class="commentCountImg" href="/2020/12/28/%E3%80%90vue%E3%80%91%E6%97%A0%E7%BC%9Dtoken%E5%88%B7%E6%96%B0/#comment-container"><span class="display-none-class">e7f879d3e6bf572def0836e8a5442218</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="e7f879d3e6bf572def0836e8a5442218">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>9 分钟  <i class="fas fa-pencil-alt"> </i>1.3 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/12/28/%E3%80%90vue%E3%80%91%E6%97%A0%E7%BC%9Dtoken%E5%88%B7%E6%96%B0/">【vue】无缝token刷新</a></h1><div class="content"><h1 id="利用axios-interceptors实现无感续期token"><a href="#利用axios-interceptors实现无感续期token" class="headerlink" title="利用axios interceptors实现无感续期token"></a>利用axios interceptors实现无感续期token</h1><p>后台有两个token, 一个是正常api用token, 一个是用来续期api token的refreshToken，正常的流程一般是 api token过期，使用refreshToken来续期，当refreshToken都过期后，就算用户登录超时了，用户每使用一次 api token, 后台都会给refreshToken 重置过期时间。最长不超过24小时。</p><h2 id="新建axios实例，设置基础配置"><a href="#新建axios实例，设置基础配置" class="headerlink" title="新建axios实例，设置基础配置"></a>新建axios实例，设置基础配置</h2><p>通过整个项目都是通过这个axios实例来调用接口的</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">const</span> instance = axios.create(&#123; <span class="attr">timeout</span>: <span class="number">1000</span> * <span class="number">12</span> &#125;)</span><br><span class="line"><span class="keyword">let</span> lastConfig = <span class="literal">null</span></span><br><span class="line"><span class="comment">// 设置请求头，默认为 json</span></span><br><span class="line">instance.defaults.headers.post[<span class="string">'Content-Type'</span>] = <span class="string">'application/json;charset=UTF-8'</span></span><br></pre></td></tr></table></figure><h2 id="通过请求拦截器注入token"><a href="#通过请求拦截器注入token" class="headerlink" title="通过请求拦截器注入token"></a>通过请求拦截器注入token</h2><p>通过axios 请求拦截器在请求之前将token加在请求头中，并且在这里备份下用户的请求配置（包括请求头，数据），这个接口请求失败后通过这个config继续请求</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// axios 请求拦截器 token 注入</span></span><br><span class="line">instance.interceptors.request.use(</span><br><span class="line">  config =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> token = getToken()</span><br><span class="line">    token &amp;&amp; (config.headers.Authorization = token)</span><br><span class="line">    <span class="comment">// 缓存访问的配置 decoup是用来解耦的</span></span><br><span class="line">    lastConfig = decoup(config)</span><br><span class="line">    <span class="keyword">return</span> config</span><br><span class="line">  &#125;,</span><br><span class="line">  error =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Promise</span>.error(error)</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h2 id="通过返回拦截器处理请求失败的情况"><a href="#通过返回拦截器处理请求失败的情况" class="headerlink" title="通过返回拦截器处理请求失败的情况"></a>通过返回拦截器处理请求失败的情况</h2><p>通过后端返回的状态，判断接口请求的情况，如果接口返回token过期，就调用refreshToken刷新token，在刷新token的接口在请求时如果还有其他接口被调用了，利用promise reslove的状态，将此阶段调用的接口状态全部暂存，当refreshToken返回了新token就使用新token继续调用之前暂存的请求，如果refreshToken返回refreshToken过期则直接要求用户重新登录</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// axois 返回拦截器 错</span></span><br><span class="line">instance.interceptors.response.use(</span><br><span class="line">  <span class="comment">// 请求成功不做处理</span></span><br><span class="line">  <span class="keyword">async</span> (response) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (resHandle[response.data.code]) &#123;</span><br><span class="line">      <span class="comment">// 这里时防止多次弹出同一个警告窗口</span></span><br><span class="line">      <span class="keyword">if</span> (isFailing) <span class="keyword">return</span></span><br><span class="line">      isFailing = <span class="literal">true</span></span><br><span class="line">      resHandle[response.data.code]()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// token过期，进入刷新token流程</span></span><br><span class="line">    <span class="keyword">if</span> (response.data.code === ruleStatus.expired) &#123;</span><br><span class="line">      <span class="keyword">const</span> config = response.config</span><br><span class="line">      <span class="comment">// 判断是否在获取新token</span></span><br><span class="line">      <span class="keyword">if</span> (!isRefreshing) &#123;</span><br><span class="line">        isRefreshing = <span class="literal">true</span></span><br><span class="line">        <span class="comment">// 调用刷新token的接口</span></span><br><span class="line">        <span class="keyword">return</span> refreshToken().then(<span class="function"><span class="params">success</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">const</span> code = success.data.code</span><br><span class="line">          <span class="comment">// refreshToken过期</span></span><br><span class="line">          <span class="keyword">if</span> (code === ruleStatus.refreshTokenInvalid) &#123;</span><br><span class="line">            MessageBox(&#123;</span><br><span class="line">              message: i18n.t(<span class="string">'http.refreshTokenInvalid'</span>),</span><br><span class="line">              duration: <span class="number">2000</span>,</span><br><span class="line">              type: <span class="string">'warning'</span></span><br><span class="line">            &#125;)</span><br><span class="line">            <span class="comment">// 跳转到登录页面</span></span><br><span class="line">            goToLogin()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">          &#125;</span><br><span class="line">          <span class="comment">// 刷新token</span></span><br><span class="line">          <span class="keyword">const</span> data = success.data.data</span><br><span class="line">          <span class="comment">// 刷新,刷新token的token</span></span><br><span class="line">          local.refreshToken = data.refreshToken</span><br><span class="line">          <span class="comment">// 刷新正常的token</span></span><br><span class="line">          local.token = formatToken(data.token_type, data.token)</span><br><span class="line">          <span class="comment">// 调用成功的回调</span></span><br><span class="line">          <span class="keyword">const</span> token = local.token</span><br><span class="line">          config.headers.Authorization = token</span><br><span class="line">          requests.forEach(<span class="function"><span class="params">cb</span> =&gt;</span> cb(token))</span><br><span class="line">          requests = []</span><br><span class="line">          <span class="keyword">return</span> instance(config)</span><br><span class="line">        &#125;).catch(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="built_in">console</span>.error(<span class="string">'refreshtoken error =&gt;'</span>, err)</span><br><span class="line">          goToLogin()</span><br><span class="line">        &#125;).finally(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">          isRefreshing = <span class="literal">false</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve</span>) =&gt;</span> &#123;</span><br><span class="line">          requests.push(<span class="function">(<span class="params">token</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">let</span> temp = <span class="literal">null</span></span><br><span class="line">            temp = lastConfig</span><br><span class="line">            temp.headers.Authorization = token</span><br><span class="line">            resolve(instance(temp))</span><br><span class="line">          &#125;)</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    isFailing = <span class="literal">true</span></span><br><span class="line">    <span class="keyword">return</span> response</span><br><span class="line">  &#125;,</span><br><span class="line">  (error) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (error.response.status) &#123;</span><br><span class="line">      <span class="keyword">const</span> status = error.response.status</span><br><span class="line">      <span class="keyword">if</span> (resHandle[status]) &#123;</span><br><span class="line">        <span class="comment">// 按照不同的错误码调用不同的方法</span></span><br><span class="line">        resHandle[status](error)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        Message(&#123;</span><br><span class="line">          message: i18n.t(<span class="string">'response.error'</span>) + status,</span><br><span class="line">          duration: <span class="number">3000</span>,</span><br><span class="line">          type: <span class="string">'warning'</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h2 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">'axios'</span></span><br><span class="line"><span class="keyword">import</span> router <span class="keyword">from</span> <span class="string">'../router'</span></span><br><span class="line"><span class="keyword">import</span> &#123; Message, MessageBox &#125; <span class="keyword">from</span> <span class="string">'element-ui'</span></span><br><span class="line"><span class="keyword">import</span> &#123; decoup, formatToken, debounce &#125; <span class="keyword">from</span> <span class="string">'@/common/js/util'</span></span><br><span class="line"><span class="keyword">import</span> local <span class="keyword">from</span> <span class="string">'../common/js/localTypes.js'</span></span><br><span class="line"><span class="keyword">import</span> base <span class="keyword">from</span> <span class="string">'./base'</span></span><br><span class="line"><span class="keyword">import</span> i18n <span class="keyword">from</span> <span class="string">'@/common/i18n/i18n.js'</span></span><br><span class="line"><span class="keyword">import</span> httpLang <span class="keyword">from</span> <span class="string">'./i18n.config.js'</span></span><br><span class="line">i18n.addNewLang(httpLang)</span><br><span class="line"><span class="keyword">let</span> isRefreshing = <span class="literal">false</span></span><br><span class="line"><span class="keyword">let</span> requests = []</span><br><span class="line"><span class="keyword">let</span> isFailing = <span class="literal">false</span></span><br><span class="line"><span class="keyword">const</span> ruleStatus = &#123;</span><br><span class="line">  noRules: <span class="string">'200200'</span>, <span class="comment">// 无权限</span></span><br><span class="line">  expired: <span class="string">'200300'</span>, <span class="comment">// 过期</span></span><br><span class="line">  invalid: <span class="string">'200001'</span>, <span class="comment">// 无效token</span></span><br><span class="line">  refreshTokenInvalid: <span class="string">'200400'</span>, <span class="comment">// 刷新token的token过期</span></span><br><span class="line">  illegalrefresh: <span class="string">'200402'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> getToken = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> local.token</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// console.log(getToken())</span></span><br><span class="line"><span class="keyword">const</span> goToLogin = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 返回登录页面</span></span><br><span class="line">  router.replace(&#123;</span><br><span class="line">    path: <span class="string">'/login'</span></span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="built_in">window</span>.location.replace(<span class="string">'/#/login'</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> refreshToken = <span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">  <span class="keyword">return</span> axios(&#123;</span><br><span class="line">    url: base.loginUrl + <span class="string">'/oauth/refresh'</span>,</span><br><span class="line">    headers: &#123;</span><br><span class="line">      Authorization: base.loginAuth,</span><br><span class="line">      <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span></span><br><span class="line">    &#125;,</span><br><span class="line">    method: <span class="string">'POST'</span>,</span><br><span class="line">    params: &#123;</span><br><span class="line">      refreshToken: local.refreshToken</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 错误情况处理方法</span></span><br><span class="line"><span class="keyword">const</span> resHandle = &#123;</span><br><span class="line">  <span class="comment">// 防止多次调用刷新token的接口 10s内只能触发一次</span></span><br><span class="line">  <span class="number">401</span>: debounce(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">    MessageBox(&#123;</span><br><span class="line">      message: i18n.t(<span class="string">'http.401'</span>) + error.response.status,</span><br><span class="line">      duration: <span class="number">2000</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    goToLogin()</span><br><span class="line">  &#125;, <span class="number">1000</span>),</span><br><span class="line">  <span class="number">403</span>: debounce(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">    Message(&#123;</span><br><span class="line">      message: i18n.t(<span class="string">'http.403'</span>) + error.response.status,</span><br><span class="line">      duration: <span class="number">2000</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;, <span class="number">1000</span>),</span><br><span class="line">  <span class="number">404</span>: debounce(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">    Message(&#123;</span><br><span class="line">      message: i18n.t(<span class="string">'http.404'</span>) + error.response.status,</span><br><span class="line">      duration: <span class="number">2000</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;, <span class="number">1000</span>),</span><br><span class="line">  <span class="number">500</span>: debounce(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">    Message(&#123;</span><br><span class="line">      message: i18n.t(<span class="string">'http.500'</span>) + error.response.status,</span><br><span class="line">      duration: <span class="number">2000</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;, <span class="number">1000</span>),</span><br><span class="line">  <span class="number">503</span> (error) &#123;</span><br><span class="line">    Message(&#123;</span><br><span class="line">      message: i18n.t(<span class="string">'http.503'</span>) + error.response.status,</span><br><span class="line">      duration: <span class="number">2000</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line">  [ruleStatus.illegalrefresh]: debounce(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    MessageBox(&#123;</span><br><span class="line">      message: i18n.t(<span class="string">'http.illegalrefresh'</span>),</span><br><span class="line">      duration: <span class="number">2000</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    goToLogin()</span><br><span class="line">  &#125;, <span class="number">1000</span>),</span><br><span class="line">  [ruleStatus.invalid]: debounce(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    MessageBox(&#123;</span><br><span class="line">      message: i18n.t(<span class="string">'http.invalid'</span>),</span><br><span class="line">      duration: <span class="number">3000</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;)</span><br><span class="line">    goToLogin()</span><br><span class="line">  &#125;, <span class="number">1000</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 设置超时时间</span></span><br><span class="line"><span class="keyword">const</span> instance = axios.create(&#123; <span class="attr">timeout</span>: <span class="number">1000</span> * <span class="number">12</span> &#125;)</span><br><span class="line"><span class="keyword">let</span> lastConfig = <span class="literal">null</span></span><br><span class="line"><span class="comment">// 设置请求头，默认为 json</span></span><br><span class="line">instance.defaults.headers.post[<span class="string">'Content-Type'</span>] = <span class="string">'application/json;charset=UTF-8'</span></span><br><span class="line"><span class="comment">// axios 请求拦截器 token 注入</span></span><br><span class="line">instance.interceptors.request.use(</span><br><span class="line">  config =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> token = getToken()</span><br><span class="line">    token &amp;&amp; (config.headers.Authorization = token)</span><br><span class="line">    <span class="comment">// 缓存访问的配置 decoup是用来解耦的</span></span><br><span class="line">    lastConfig = decoup(config)</span><br><span class="line">    <span class="keyword">return</span> config</span><br><span class="line">  &#125;,</span><br><span class="line">  error =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">Promise</span>.error(error)</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br><span class="line"><span class="comment">// axois 返回拦截器 错</span></span><br><span class="line">instance.interceptors.response.use(</span><br><span class="line">  <span class="comment">// 请求成功不做处理</span></span><br><span class="line">  <span class="keyword">async</span> (response) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (resHandle[response.data.code]) &#123;</span><br><span class="line">      <span class="keyword">if</span> (isFailing) <span class="keyword">return</span></span><br><span class="line">      isFailing = <span class="literal">true</span></span><br><span class="line">      resHandle[response.data.code]()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (response.data.code === ruleStatus.expired) &#123;</span><br><span class="line">      <span class="keyword">const</span> config = response.config</span><br><span class="line">      <span class="keyword">if</span> (!isRefreshing) &#123;</span><br><span class="line">        isRefreshing = <span class="literal">true</span></span><br><span class="line">        <span class="keyword">return</span> refreshToken().then(<span class="function"><span class="params">success</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">const</span> code = success.data.code</span><br><span class="line">          <span class="keyword">if</span> (code === ruleStatus.refreshTokenInvalid) &#123;</span><br><span class="line">            MessageBox(&#123;</span><br><span class="line">              message: i18n.t(<span class="string">'http.refreshTokenInvalid'</span>),</span><br><span class="line">              duration: <span class="number">2000</span>,</span><br><span class="line">              type: <span class="string">'warning'</span></span><br><span class="line">            &#125;)</span><br><span class="line">            goToLogin()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">          &#125;</span><br><span class="line">          <span class="comment">// 刷新token</span></span><br><span class="line">          <span class="keyword">const</span> data = success.data.data</span><br><span class="line">          <span class="comment">// 刷新,刷新token的token</span></span><br><span class="line">          local.refreshToken = data.refreshToken</span><br><span class="line">          <span class="comment">// setLocalStorage(localTypes.refreshToken, data.refreshToken)</span></span><br><span class="line">          <span class="comment">// 刷新正常的token</span></span><br><span class="line">          local.token = formatToken(data.token_type, data.token)</span><br><span class="line">          <span class="comment">// setLocalStorage(localTypes.token, formatToken(data.token_type, data.token))</span></span><br><span class="line">          <span class="comment">// 调用成功的回调</span></span><br><span class="line">          <span class="comment">// const token = getLocalStorage(localTypes.token)</span></span><br><span class="line">          <span class="keyword">const</span> token = local.token</span><br><span class="line">          config.headers.Authorization = token</span><br><span class="line">          requests.forEach(<span class="function"><span class="params">cb</span> =&gt;</span> cb(token))</span><br><span class="line">          requests = []</span><br><span class="line">          <span class="keyword">return</span> instance(config)</span><br><span class="line">        &#125;).catch(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="built_in">console</span>.error(<span class="string">'refreshtoken error =&gt;'</span>, err)</span><br><span class="line">          goToLogin()</span><br><span class="line">        &#125;).finally(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">          isRefreshing = <span class="literal">false</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve</span>) =&gt;</span> &#123;</span><br><span class="line">          requests.push(<span class="function">(<span class="params">token</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">let</span> temp = <span class="literal">null</span></span><br><span class="line">            temp = lastConfig</span><br><span class="line">            temp.headers.Authorization = token</span><br><span class="line">            resolve(instance(temp))</span><br><span class="line">          &#125;)</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    isFailing = <span class="literal">true</span></span><br><span class="line">    <span class="keyword">return</span> response</span><br><span class="line">  &#125;,</span><br><span class="line">  (error) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (error.response.status) &#123;</span><br><span class="line">      <span class="keyword">const</span> status = error.response.status</span><br><span class="line">      <span class="keyword">if</span> (resHandle[status]) &#123;</span><br><span class="line">        resHandle[status](error)</span><br><span class="line">        <span class="comment">// 按照不同的错误码调用不同的方法</span></span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        Message(&#123;</span><br><span class="line">          message: i18n.t(<span class="string">'response.error'</span>) + status,</span><br><span class="line">          duration: <span class="number">3000</span>,</span><br><span class="line">          type: <span class="string">'warning'</span></span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> error</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> instance</span><br></pre></td></tr></table></figure></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/axios-token-refresh-token/">axios token refresh token</a></div>  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-12-24  <a class="commentCountImg" href="/2020/12/24/HTML%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/#comment-container"><span class="display-none-class">d3f1633a4e268370e1740904d1325125</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="d3f1633a4e268370e1740904d1325125">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>12 分钟  <i class="fas fa-pencil-alt"> </i>1.7 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/12/24/HTML%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/">HTML理论知识</a></h1><div class="content"><h1 id="HTML"><a href="#HTML" class="headerlink" title="HTML"></a>HTML</h1><h2 id="HTML-简介"><a href="#HTML-简介" class="headerlink" title="HTML 简介"></a>HTML 简介</h2><p>html是缩写 全程 Hyper Text Marked Language (超文本标记语言)</p><p><strong>超文本</strong></p><p>超级文本</p><p><strong>标记：</strong></p><p>标示</p><p><strong>语言：</strong></p><p>汉语英语法语，html是机器语言的一种</p><p><strong>总结：</strong><br>比普通文本牛并且又标示符号的机器语言，html是为网页创建的一种标记语言，也就是说他是运行在浏览器上。</p><p><strong>版本：</strong></p><p>目前的版本是HTML5</p><h2 id="为什么要创建一个html呢"><a href="#为什么要创建一个html呢" class="headerlink" title="为什么要创建一个html呢"></a>为什么要创建一个html呢</h2><p>.html 是一个扩展名，靠浏览器来解析的文件。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    </span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="HTML字符集"><a href="#HTML字符集" class="headerlink" title="HTML字符集"></a>HTML字符集</h2><ol><li>网页种特殊意义的字符</li><li>键盘上没有的字符</li></ol><p><strong>规则</strong></p><p>以&amp;开始以;结尾</p><p>例子</p><p><a href="https://www.runoob.com/charsets/ref-utf-basic-latin.html">字符集</a></p><p><a href="https://www.runoob.com/charsets/ref-utf-latin1-supplement.html">字符集2</a></p><p><a href="https://www.runoob.com/charsets/ref-utf-latin-extended-a.html">字符集3</a></p><p><a href="https://www.runoob.com/charsets/ref-utf-latin-extended-b.html">字符集4</a></p><h2 id="HTML-块级元素"><a href="#HTML-块级元素" class="headerlink" title="HTML 块级元素"></a>HTML 块级元素</h2><p><strong>特点：</strong></p><ul><li>总是在新行上开始</li><li>高度和行高以及内外边距都是可控制的</li><li>宽度缺省默认就是100%宽度</li></ul><p><strong>功能：</strong></p><p>主要是用来搭建网站架构，页面布局，承载内容</p><ul><li>div: 架构、结构</li><li>p: 段落</li><li>h1-h6: 标题</li><li>ol 有序列表配合 li 使用</li><li>ul 无序列表配合 li 使用</li><li>hr 水平线 单标签</li><li>noscript: chrome禁止javascript脚本代码运行时的提示内容</li><li>table 表格</li><li>form 表单</li><li>pre 定义预格式文本，一般配合code使用</li></ul><p><strong>所有块级元素：</strong></p><p>h1-h6&gt;&gt;1-6级标题</p><p>p&gt;&gt;段落</p><p>div&gt;&gt;定义文档中的节</p><p>ul&gt;&gt;定义无序列表</p><p>ol&gt;&gt;定义有序列表</p><p>li&gt;&gt;定义无序列表与有序列表中的项</p><p>hr&gt;&gt;水平线</p><p>address&gt;&gt;定义文档作者或拥有者的联系信息</p><p>blockquote&gt;&gt;定义长的引用</p><p>pre&gt;&gt;定义预格式文本</p><p>form&gt;&gt;定义表单</p><p>fieldset&gt;&gt;定义围绕表单中元素的边框</p><p>legend&gt;&gt;定义 fieldset 元素的标题</p><p>figure&gt;&gt;定义媒介内容的分组，以及它们的标题。</p><p>figcaption&gt;&gt;定义 figure 元素的标题</p><p>audio&gt;&gt;定义声音内容</p><p>video&gt;&gt;定义视频</p><p>nav&gt;&gt;定义导航链接</p><p>dl&gt;&gt;定义定义列表</p><p>dt&gt;&gt;定义定义列表中的项目</p><p>dd&gt;&gt;定义定义列表中项目的描述</p><p>menu&gt;&gt;定义命令的菜单/列表</p><p>table&gt;&gt;定义表格</p><p>caption&gt;&gt;定义表格标题</p><p>tbody&gt;&gt;定义表格主体</p><p>thead&gt;&gt;定义表格头部</p><p>tfoot&gt;&gt;定义表格中的表注内容（脚注）</p><p>tr&gt;&gt;定义表格中的行</p><p>th&gt;&gt;定义表格中的表头单元格</p><p>colgroup&gt;&gt;定义表格中供格式化的列组</p><p>col&gt;&gt;定义表格中一个或多个列的属性值。【在colgroup中使用 】</p><p>header&gt;&gt;定义 section 或 page 的页眉</p><p>footer&gt;&gt;定义 section 或 page 的页脚</p><p>section&gt;&gt;定义文档中的节（section、区段）。比如章节、页眉、页脚或文档中的其他部分</p><p>article&gt;&gt;定义文章</p><p>aside&gt;&gt;定义页面内容之外的内容。【可用作文章的侧栏。】</p><p>datails&gt;&gt;定义元素的细节。【用于描述有关文档或文档片段的详细信息。】</p><p>summary&gt;&gt;为 details 元素定义可见的标题。</p><p><strong>规范：</strong></p><p>段落需要用：P, 结构用:div</p><h2 id="行内元素"><a href="#行内元素" class="headerlink" title="行内元素"></a>行内元素</h2><h3 id="特点："><a href="#特点：" class="headerlink" title="特点："></a>特点：</h3><ul><li>和其他元素都在一行显示不独占一行</li><li>高、行高、顶部、底部、的边距是不可以修改的</li><li>宽度就是文字的宽度<h3 id="功能："><a href="#功能：" class="headerlink" title="功能："></a>功能：</h3>用户加强内容显示，控制细节<h3 id="所有元素："><a href="#所有元素：" class="headerlink" title="所有元素："></a>所有元素：</h3></li></ul><h3 id="常用标签："><a href="#常用标签：" class="headerlink" title="常用标签："></a>常用标签：</h3><ul><li>span: 文档中的节</li><li>a: 跳转页面用的<ul><li>新页面打开<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"https://baidu.com"</span> <span class="attr">target</span>=<span class="string">"__blank"</span>&gt;</span>我要去百度<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li>本页面打开<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"https://baidu.com"</span>&gt;</span>我要去百度<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ul></li><li>code: 代码文本</li><li>em: 文字倾斜</li><li>i: 文字倾斜 但是一般用作图标</li><li>b: 文字加粗</li><li>strong: 文字加粗</li></ul><p>br&gt;&gt;定义换行</p><p>a&gt;&gt;定义超链接</p><p>i&gt;&gt;定义文字倾斜</p><p>b&gt;&gt;定义文字加粗</p><p>em&gt;&gt;定义文字倾斜，语义更加强调</p><p>abbr&gt;&gt;定义缩写</p><p>bdi&gt;&gt; 定义文本的文本方向，使其脱离其周围文本的方向设置</p><p>bdo&gt;&gt;定义文字方向</p><p>cite&gt;&gt;定义引用</p><p>code&gt;&gt;定义计算机代码文本</p><p>dfn&gt;&gt;定义定义项目</p><p>ins&gt;&gt;定义被插入文本</p><p>kbd&gt;&gt;定义键盘文本</p><p>Mark&gt;&gt;定义有记号的文本</p><p>q&gt;&gt;定义短的引用</p><p>rp&gt;&gt;定义若浏览器不支持 ruby 元素显示的内容</p><p>rt&gt;&gt;定义 ruby 注释的解释</p><p>ruby&gt;&gt;定义 ruby 注释</p><p>samp&gt;&gt;定义计算机代码样本</p><p>small&gt;&gt;定义小号文本</p><p>strong&gt;&gt;定义语气更为强烈的强调文本，文字加粗</p><p>sup&gt;&gt;定义上标文本</p><p>sub&gt;&gt;定义下标文本</p><p>time&gt;&gt;定义日期/时间</p><p>var&gt;&gt;定义文本的变量部分</p><p>wbr&gt;&gt;定义可能的换行符</p><p>label&gt;&gt;定义 input 元素的标注</p><p>datalist&gt;&gt;定义下拉列表</p><p>Keygen&gt;&gt;定义生成密钥。</p><p>output&gt;&gt;定义输出的一些类型。【如脚本输出】</p><p>map&gt;&gt;定义图像映射</p><p>area&gt;&gt;定义图像地图内部的区域</p><p>source&gt;&gt;定义媒介源</p><p>track&gt;&gt;定义用在媒体播放器中的文本轨道</p><p>link&gt;&gt;定义文档与外部资源的关系</p><p>command&gt;&gt;定义命令按钮</p><p>style&gt;&gt;定义文档的样式信息</p><p>span&gt;&gt;定义文档中的节</p><p>base&gt;&gt;定义页面中所有链接的默认地址或默认目标</p><h2 id="行内块元素"><a href="#行内块元素" class="headerlink" title="行内块元素"></a>行内块元素</h2><h3 id="功能"><a href="#功能" class="headerlink" title="功能"></a>功能</h3><ul><li>用户加强内容显示，控制细节</li></ul><h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><ul><li>和其他元素都在一行显示，不独占一行</li><li>高、行高、顶部、底部边距都是可修改的</li><li>宽度默认就是内容的宽度，但是是可修改的</li></ul><h3 id="元素"><a href="#元素" class="headerlink" title="元素"></a>元素</h3><ul><li><p>input： 定义输入控件</p><ul><li><p>type: text 默认输入文本</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>type: password</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"password"</span> <span class="attr">placeholder</span>=<span class="string">"密码..."</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>其他</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">placeholder</span>=<span class="string">"邮箱..."</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"password"</span> <span class="attr">placeholder</span>=<span class="string">"密码..."</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"checkbox"</span> <span class="attr">name</span>=<span class="string">"1"</span>&gt;</span> </span><br><span class="line"><span class="comment">&lt;!-- radio 当name一致时就是单选  --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"radio"</span> <span class="attr">name</span>=<span class="string">"1"</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"radio"</span> <span class="attr">name</span>=<span class="string">"1"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"radio"</span> <span class="attr">name</span>=<span class="string">"1"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"radio"</span> <span class="attr">name</span>=<span class="string">"1"</span>&gt;</span></span><br><span class="line"> <span class="comment">&lt;!-- 重置  --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"reset"</span>&gt;</span></span><br><span class="line"> <span class="comment">&lt;!-- 提交  --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"submit"</span>&gt;</span></span><br><span class="line"> <span class="comment">&lt;!-- 按钮  --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"button"</span>&gt;</span></span><br><span class="line"> <span class="comment">&lt;!-- 文件  --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"file"</span> <span class="attr">name</span>=<span class="string">"文件提交"</span> <span class="attr">id</span>=<span class="string">""</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ul></li><li><p>textarea 文本域</p></li><li><p>select 选项框，配合option使用</p></li><li><p>img 放置图片</p></li></ul><h3 id="所有行内块级元素"><a href="#所有行内块级元素" class="headerlink" title="所有行内块级元素"></a>所有行内块级元素</h3><p>img&gt;&gt;定义图像</p><p>input&gt;&gt;定义输入控件</p><p>meter &gt;&gt;定义预定义范围内的度量</p><p>progress&gt;&gt;定义任何类型的任务的进度</p><p>textarea&gt;&gt;定义多行的文本输入控件</p><p>button&gt;&gt;定义按钮</p><p>select&gt;&gt;定义选择列表（下拉列表）</p><p>iframe&gt;&gt;定义内联框架</p><p>canvas&gt;&gt;定义图形</p><p>td&gt;&gt;定义表格中的单元格</p><h2 id="HTML规范"><a href="#HTML规范" class="headerlink" title="HTML规范"></a>HTML规范</h2><h3 id="块级元素与块级元素平级，行内元素与行内元素平级"><a href="#块级元素与块级元素平级，行内元素与行内元素平级" class="headerlink" title="块级元素与块级元素平级，行内元素与行内元素平级"></a>块级元素与块级元素平级，行内元素与行内元素平级</h3><h3 id="块元素可以包含内联元素或某些块元素，但内联元素不能包含块元素，它只能包含其它的内联元素"><a href="#块元素可以包含内联元素或某些块元素，但内联元素不能包含块元素，它只能包含其它的内联元素" class="headerlink" title="块元素可以包含内联元素或某些块元素，但内联元素不能包含块元素，它只能包含其它的内联元素"></a>块元素可以包含内联元素或某些块元素，但内联元素不能包含块元素，它只能包含其它的内联元素</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">span</span>&gt;</span><span class="tag">&lt;<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="有几个特殊的块级元素只能包含内嵌元素，不能再包含块级元素"><a href="#有几个特殊的块级元素只能包含内嵌元素，不能再包含块级元素" class="headerlink" title="有几个特殊的块级元素只能包含内嵌元素，不能再包含块级元素"></a>有几个特殊的块级元素只能包含内嵌元素，不能再包含块级元素</h3><p>h1、h2、h3、h4、h5、h6、p、dt</p><h3 id="块级元素不能放在标签p里面"><a href="#块级元素不能放在标签p里面" class="headerlink" title="块级元素不能放在标签p里面"></a>块级元素不能放在标签p里面</h3><h3 id="li-标签可以包含-div-标签，因为li-和-div-标签都是装载内容的容器"><a href="#li-标签可以包含-div-标签，因为li-和-div-标签都是装载内容的容器" class="headerlink" title="li 标签可以包含 div 标签，因为li 和 div 标签都是装载内容的容器"></a>li 标签可以包含 div 标签，因为li 和 div 标签都是装载内容的容器</h3></div><div class="index-category-tag">  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-11-21  <a class="commentCountImg" href="/2020/11/21/%E7%8A%80%E7%9A%AE%E6%BC%86%E5%99%A8%E7%9A%84%E4%B8%80%E8%88%AC%E5%88%B6%E4%BD%9C%E6%AD%A5%E9%AA%A4/#comment-container"><span class="display-none-class">45fc1df1e957c24a19a118558d40301a</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="45fc1df1e957c24a19a118558d40301a">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>3 分钟  <i class="fas fa-pencil-alt"> </i>0.5 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/11/21/%E7%8A%80%E7%9A%AE%E6%BC%86%E5%99%A8%E7%9A%84%E4%B8%80%E8%88%AC%E5%88%B6%E4%BD%9C%E6%AD%A5%E9%AA%A4/">【花活】犀皮漆器的一般制作步骤</a></h1><div class="content"><h2 id="犀皮漆器一般步骤"><a href="#犀皮漆器一般步骤" class="headerlink" title="犀皮漆器一般步骤"></a>犀皮漆器一般步骤</h2><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h2><ol><li>制作简易的荫箱 温度20摄氏度，湿度75%</li><li>笔刷清洗<ul><li>松节油-&gt;保鲜膜松节油浸泡-&gt;揭开保鲜膜用植物油清洗-&gt;水冲洗<h2 id="制作步骤，注意事项"><a href="#制作步骤，注意事项" class="headerlink" title="制作步骤，注意事项"></a>制作步骤，注意事项</h2></li></ul></li></ol><h3 id="打磨"><a href="#打磨" class="headerlink" title="打磨"></a>打磨</h3><p>使用400目砂纸打磨器物表面粗糙使得大漆更易附着</p><h3 id="上生漆"><a href="#上生漆" class="headerlink" title="上生漆"></a>上生漆</h3><p>漆要薄，均匀，太厚会起皱，太会露底（阴干8小时）后再用400目的砂纸进行打磨，如果露底了，就需要补漆</p><h3 id="打埝"><a href="#打埝" class="headerlink" title="打埝"></a>打埝</h3><p><strong>注意：</strong></p><ul><li>打埝用的漆的颜色任选。</li><li>加蛋清（蛋清1：3大漆）的比例来调制埝漆</li><li>打埝的工具有很多种，牙签、丝瓜瓤、钢丝球等类似特性的物体都可以使用</li><li>埝的疏密程度和高度都可以自己控制</li><li>埝干燥需要15 - 20天</li><li>刚打的埝先在正常环境下进行放置，防止埝塌陷</li></ul><p><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20201121232826.png" alt="注意事项"></p><p>调埝漆需要耐心，有拔丝的效果即可开始打埝</p><h3 id="髤色漆"><a href="#髤色漆" class="headerlink" title="髤色漆"></a>髤色漆</h3><p><strong>注意：这个步骤一定要等到埝完全干透才能开始</strong><br><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20201121232908.png" alt="髤色漆"></p><p>将用到的色漆使用10%左右的稀释剂稀释<br>埝干后，髤黑色漆,黑色漆干后髤红色漆、红色漆用手去触碰有点粘手，但不会把漆黏下即可贴金，贴金等干燥后，上透明漆，漆尽量涂的薄一些。这个步骤可以重复多次，一般15 - 60层不等。</p><h3 id="打磨抛光"><a href="#打磨抛光" class="headerlink" title="打磨抛光"></a>打磨抛光</h3><p><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20201121232933.png"></p><p>按顺序耐心打磨，注意不要磨穿了。</p><h3 id="效果图"><a href="#效果图" class="headerlink" title="效果图"></a>效果图</h3><p><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20201121233101.png"></p></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/%E6%BC%86%E5%99%A8/">漆器</a></div>  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><div style="color:#3273dc;font-size:1.8rem"><i class="fas fa-arrow-alt-circle-up"></i> </div><i class="far fa-calendar-plus"> </i>2020-11-01  <a class="commentCountImg" href="/2020/11/01/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91vue%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E5%AE%9E%E7%8E%B0-1/#comment-container"><span class="display-none-class">6b9a5a6dc47d6160588de08ac4058b31</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="6b9a5a6dc47d6160588de08ac4058b31">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>12 分钟  <i class="fas fa-pencil-alt"> </i>1.8 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/11/01/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91vue%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E5%AE%9E%E7%8E%B0-1/">【前端】vue权限管理</a></h1><div class="content"><h2 id="需求"><a href="#需求" class="headerlink" title="需求"></a>需求</h2><ol><li>后台管理界面不同的用户根据角色的不同显示不同的功能模块</li><li>前端页面能够在任一模块下添加子路由，并能够配置权限</li><li>按钮权限控制<h2 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h2></li></ol><p>用户登录的时，获取用户token,在跳转到主页面时根据用户token向后端请求对应的路由表，前端根据路由表与本地已导入的模块对比，双方都存在的情况下动态生成路由通过router.addRoutes方法载入。</p></div><div class="index-category-tag">  <hr></div><div class="level is-mobile is-flex"><div class="level-start"><div class="level-item"><a class="article-more button is-small size-small link-muted" href="/2020/11/01/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91vue%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E5%AE%9E%E7%8E%B0-1/#more">阅读更多&gt;&gt;</a></div></div><div class="level-start"><div class="level-item has-text-grey is-size-7"><time datetime="2020-12-29T07:28:43.599Z"><i class="far fa-calendar-check"> 最后修改: </i>2020-12-29</time></div></div></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-09-26  <a class="commentCountImg" href="/2020/09/26/%E3%80%90node%E3%80%91node%E7%88%AC%E8%99%AB%E5%AE%9E%E8%B7%B5/#comment-container"><span class="display-none-class">dd61ab2cb8e4f453c92a1d038bbdf909</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="dd61ab2cb8e4f453c92a1d038bbdf909">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>4 分钟  <i class="fas fa-pencil-alt"> </i>0.6 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/09/26/%E3%80%90node%E3%80%91node%E7%88%AC%E8%99%AB%E5%AE%9E%E8%B7%B5/">【node】node爬虫实践</a></h1><div class="content"><p>完整代码已经上传到我的github</p><ul><li><a href="https://github.com/WXperia/Spy-tools">Spy-tools</a></li></ul><p>百度图片爬取核心代码</p><p>百度搜索获取图片时，页面加载方式是下拉加载，为了克服这个问题，就了解了下puppeteer这个库，这个库能够打开一个沙盒浏览器，然后使用代码模拟正常的操作，点击，输入之类的，有点类似于auto.js。</p><h1 id="爬虫核心api"><a href="#爬虫核心api" class="headerlink" title="爬虫核心api"></a>爬虫核心api</h1><ul><li>page.$() 获取页面中的元素，与jquery一致</li><li>page.evaluate(()=&gt;{},element) 相当于当前打开页面的控制台，element默认为window，这个方法是获取页面内容的关键</li><li>page.goto(URL) 打开某个网页</li><li>page.on() 监听页面中调用的方法 比如console</li></ul><h1 id="sleep方法"><a href="#sleep方法" class="headerlink" title="sleep方法"></a>sleep方法</h1><p>用于控制等待时间，防止网站反爬</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">sleep</span></span>&#123;</span><br><span class="line">	<span class="keyword">async</span> sleep(time)&#123;</span><br><span class="line">		<span class="built_in">console</span>.log(<span class="string">`now to sleep <span class="subst">$&#123;time&#125;</span>ms`</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>( <span class="function"><span class="params">next</span>=&gt;</span> &#123;</span><br><span class="line">			setTimeout(<span class="function"><span class="params">()</span>=&gt;</span> &#123;</span><br><span class="line">				next();</span><br><span class="line">			&#125;, time);</span><br><span class="line">		&#125;)</span><br><span class="line">	&#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">module</span>.exports = <span class="keyword">new</span> sleep();</span><br></pre></td></tr></table></figure><h1 id="模仿真人下拉刷新"><a href="#模仿真人下拉刷新" class="headerlink" title="模仿真人下拉刷新"></a>模仿真人下拉刷新</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">  <span class="comment">// 模拟滚动，获取足够的图片</span></span><br><span class="line">  <span class="keyword">const</span> scrollTimer = page.evaluate(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">//这个作用域的this不能改变,否则无法正常获取页面元素</span></span><br><span class="line">    <span class="keyword">const</span> DOWLOAD_SIZE = <span class="number">1000</span>; <span class="comment">// 一次性需要下载图片的数量</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> totalSize = <span class="number">0</span></span><br><span class="line">        <span class="keyword">let</span> totalHeight = <span class="number">0</span></span><br><span class="line">        <span class="keyword">let</span> distance = <span class="number">600</span></span><br><span class="line">        <span class="keyword">let</span> timer = setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">window</span>.scrollBy(<span class="number">0</span>, distance)</span><br><span class="line">            totalHeight += distance</span><br><span class="line">            <span class="keyword">let</span> imgList = <span class="built_in">Array</span>.from(<span class="built_in">document</span>.getElementsByClassName(<span class="string">'imgitem'</span>))</span><br><span class="line">            <span class="comment">// 处理图片数量不够的情况</span></span><br><span class="line">            <span class="keyword">let</span> documentScrollHeight = <span class="built_in">document</span>.body.scrollHeight</span><br><span class="line">            <span class="keyword">let</span> isMaxed = totalHeight &gt;= documentScrollHeight</span><br><span class="line">            totalSize = imgList.length</span><br><span class="line">            <span class="keyword">if</span>(totalSize &gt;= DOWLOAD_SIZE || isMaxed)&#123;</span><br><span class="line">                clearInterval(timer)</span><br><span class="line">                resolve()</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="number">200</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h1 id="获取页面内的数据"><a href="#获取页面内的数据" class="headerlink" title="获取页面内的数据"></a>获取页面内的数据</h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> data = <span class="keyword">await</span> page.evaluate( <span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">    <span class="keyword">let</span> ret = []</span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">imgData</span> </span>&#123;</span><br><span class="line">      <span class="keyword">constructor</span>(title, url) &#123;</span><br><span class="line">        <span class="keyword">this</span>.title = title</span><br><span class="line">        <span class="keyword">this</span>.url = url</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> itemlist = <span class="built_in">document</span>.getElementsByClassName(<span class="string">'imgitem'</span>)</span><br><span class="line">    <span class="built_in">Array</span>.from(itemlist).forEach(<span class="function"><span class="params">li</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">let</span> title = li.getAttribute(<span class="string">"data-title"</span>)</span><br><span class="line">      <span class="keyword">let</span> img = li.getElementsByClassName(<span class="string">'main_img'</span>)[<span class="number">0</span>]</span><br><span class="line">      <span class="keyword">let</span> url = img.getAttribute(<span class="string">'src'</span>)</span><br><span class="line">      ret.push(<span class="keyword">new</span> imgData(title, url))</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">return</span> ret</span><br><span class="line">  &#125;)</span><br></pre></td></tr></table></figure><h1 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">let</span> request = <span class="built_in">require</span>(<span class="string">"request"</span>);</span><br><span class="line"><span class="keyword">let</span> fs = <span class="built_in">require</span>(<span class="string">"fs"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Ut</span> </span>&#123;</span><br><span class="line">  <span class="keyword">static</span> downImg(opts = &#123;&#125;, path = <span class="string">''</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      request</span><br><span class="line">        .get(opts)</span><br><span class="line">        .on(<span class="string">'response'</span>, (response) =&gt; &#123;</span><br><span class="line">          <span class="comment">// console.log("img type:", response.headers['content-type'])</span></span><br><span class="line">        &#125;)</span><br><span class="line">        .pipe(fs.createWriteStream(path))</span><br><span class="line">        .on(<span class="string">"error"</span>, (e) =&gt; &#123;</span><br><span class="line">          <span class="comment">// console.log("pipe error", e)</span></span><br><span class="line">          resolve(<span class="string">''</span>);</span><br><span class="line">        &#125;)</span><br><span class="line">        .on(<span class="string">"finish"</span>, () =&gt; &#123;</span><br><span class="line">          <span class="comment">// console.log("finish");</span></span><br><span class="line">          resolve(<span class="string">"ok"</span>);</span><br><span class="line">        &#125;)</span><br><span class="line">        .on(<span class="string">"close"</span>, () =&gt; &#123;</span><br><span class="line">          <span class="comment">// console.log("close");</span></span><br><span class="line">        &#125;)</span><br><span class="line"> </span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="built_in">module</span>.exports = Ut;</span><br></pre></td></tr></table></figure><p>一个一个下载</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> len = data.length</span><br><span class="line">    <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">getData</span>(<span class="params">index,list</span>) </span>&#123;</span><br><span class="line">      <span class="keyword">if</span>(!list[index]) &#123;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">      &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> item = list[index]</span><br><span class="line">        <span class="keyword">let</span> url = item.url</span><br><span class="line">        <span class="keyword">let</span> path = <span class="string">`<span class="subst">$&#123;FILE_PATH&#125;</span>/<span class="subst">$&#123;index&#125;</span>.jpg`</span>;</span><br><span class="line">        <span class="keyword">if</span> (<span class="regexp">/http/g</span>.test(url)) &#123;</span><br><span class="line">            <span class="keyword">let</span> opts = &#123;</span><br><span class="line">              url: url,</span><br><span class="line">            &#125;;</span><br><span class="line">          log(chalk.green(<span class="string">`正在下载第<span class="subst">$&#123;index&#125;</span>张共<span class="subst">$&#123;len&#125;</span>张...`</span>))</span><br><span class="line">          <span class="keyword">await</span> Ut.downImg(opts, path); </span><br><span class="line">          log(chalk.green(<span class="string">`正在下载第<span class="subst">$&#123;index&#125;</span>张下载成功`</span>))</span><br><span class="line">        &#125;</span><br><span class="line">        index ++</span><br><span class="line">        <span class="keyword">await</span> getData(index,list)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (len) &#123;</span><br><span class="line">      <span class="keyword">await</span> getData(<span class="number">0</span>,data)</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><div class="index-category-tag">  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-09-08  <a class="commentCountImg" href="/2020/09/08/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91Vue%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/#comment-container"><span class="display-none-class">a60ab0bd6ea4ad1bc941076a7d3088c6</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="a60ab0bd6ea4ad1bc941076a7d3088c6">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>10 分钟  <i class="fas fa-pencil-alt"> </i>1.5 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/09/08/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91Vue%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/">【前端】Vue组件通信</a></h1><div class="content"><h1 id="props与-emit"><a href="#props与-emit" class="headerlink" title="props与$emit"></a>props与$emit</h1><p>最常用的组合，props适合用作父组件传值给子组件，$emit经常用于基础组件封装的时间派发和数据传递（子组件向父组件传值）<br>props在子组件中为只读属性，如果强行赋值修改，Vue会在控制台打印警告</p><p>$emit 派发事件只有父节点才能监听到，如果跨层级，需要一级一级的使用$emit派发</p><p>贴个基本使用、props向下传递同样有这个问题</p><p><strong>父组件</strong></p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'parent'</span>, &#123;</span><br><span class="line">  template:<span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;this is parent component!&lt;/p&gt;</span></span><br><span class="line"><span class="string">      &lt;child :message="message" @getChildData="getChildData"&gt;&lt;/child&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  data() &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      message: <span class="string">'hello'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods:&#123;</span><br><span class="line">    <span class="comment">// 执行子组件触发的事件</span></span><br><span class="line">    getChildData(val) &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(val);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><strong>子组件</strong></p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// 子组件</span></span><br><span class="line">Vue.component(<span class="string">'child'</span>, &#123;</span><br><span class="line">  template:<span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;input type="text" v-model="myMessage" @input="passData(myMessage)"&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 得到父组件传递过来的数据</span></span><br><span class="line"><span class="comment">   * 这里的定义最好是写成数据校验的形式，免得得到的数据是我们意料之外的</span></span><br><span class="line"><span class="comment">   *</span></span><br><span class="line"><span class="comment">   * props: &#123;</span></span><br><span class="line"><span class="comment">   *   message: &#123;</span></span><br><span class="line"><span class="comment">   *     type: String,</span></span><br><span class="line"><span class="comment">   *     default: ''</span></span><br><span class="line"><span class="comment">   *   &#125;</span></span><br><span class="line"><span class="comment">   * &#125;</span></span><br><span class="line"><span class="comment">   *</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  props:[<span class="string">'message'</span>], </span><br><span class="line">  data() &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="comment">// 这里是必要的，因为你不能直接修改 props 的值</span></span><br><span class="line">      myMessage: <span class="keyword">this</span>.message</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods:&#123;</span><br><span class="line">    passData(val) &#123;</span><br><span class="line">      <span class="comment">// 数据状态变化时触发父组件中的事件</span></span><br><span class="line">      <span class="keyword">this</span>.$emit(<span class="string">'getChildData'</span>, val);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line">    </span><br><span class="line"><span class="keyword">var</span> app=<span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;parent /&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><ol><li>父组件通过props传递给子组件message，并且监听了子组件的getChildData事件，获取了子组件传递的val并打印</li><li>子组件通过props获取到了父组件传递的值，并且使用$emit将myMessage传递给了父组件</li></ol><h1 id="attrs-和-listeners"><a href="#attrs-和-listeners" class="headerlink" title="$attrs 和 $listeners"></a>$attrs 和 $listeners</h1><p>Vue 2.4 新增的两个属性，不关注官方文档的话，应该用的不是那么多，这两个属性对于上面提到的只能传递一级的问题有一定的效果，再也不用一个事件层层$emit，一个数据代代props了。</p><p>简单来说 $attrs 就是跨层级版的 props, $listeners就是跨层级的$emit</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 组件A</span></span><br><span class="line">Vue.component(<span class="string">'A'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;this is parent component!&lt;/p&gt;</span></span><br><span class="line"><span class="string">      &lt;B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"&gt;&lt;/B&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  data() &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      message: <span class="string">'hello'</span>,</span><br><span class="line">      messagec: <span class="string">'hello c'</span> <span class="comment">//传递给c组件的数据</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    <span class="comment">// 执行B子组件触发的事件</span></span><br><span class="line">    getChildData(val) &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">`这是来自B组件的数据：<span class="subst">$&#123;val&#125;</span>`</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 执行C子组件触发的事件</span></span><br><span class="line">    getCData(val) &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">`这是来自C组件的数据：<span class="subst">$&#123;val&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件B</span></span><br><span class="line">Vue.component(<span class="string">'B'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;input type="text" v-model="mymessage" @input="passData(mymessage)"&gt; </span></span><br><span class="line"><span class="string">      &lt;!-- C组件中能直接触发 getCData 的原因在于：B组件调用 C组件时，使用 v-on 绑定了 $listeners 属性 --&gt;</span></span><br><span class="line"><span class="string">      &lt;!-- 通过v-bind 绑定 $attrs 属性，C组件可以直接获取到 A组件中传递下来的 props（除了 B组件中 props声明的） --&gt;</span></span><br><span class="line"><span class="string">      &lt;C v-bind="$attrs" v-on="$listeners"&gt;&lt;/C&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 得到父组件传递过来的数据</span></span><br><span class="line"><span class="comment">   * 这里的定义最好是写成数据校验的形式，免得得到的数据是我们意料之外的</span></span><br><span class="line"><span class="comment">   *</span></span><br><span class="line"><span class="comment">   * props: &#123;</span></span><br><span class="line"><span class="comment">   *   message: &#123;</span></span><br><span class="line"><span class="comment">   *     type: String,</span></span><br><span class="line"><span class="comment">   *     default: ''</span></span><br><span class="line"><span class="comment">   *   &#125;</span></span><br><span class="line"><span class="comment">   * &#125;</span></span><br><span class="line"><span class="comment">   *</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  props: [<span class="string">'message'</span>],</span><br><span class="line">  data()&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      mymessage: <span class="keyword">this</span>.message</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    passData(val)&#123;</span><br><span class="line">      <span class="comment">//触发父组件中的事件</span></span><br><span class="line">      <span class="keyword">this</span>.$emit(<span class="string">'getChildData'</span>, val)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件C</span></span><br><span class="line">Vue.component(<span class="string">'C'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)"&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    passCData(val) &#123;</span><br><span class="line">      <span class="comment">// 触发父组件A中的事件</span></span><br><span class="line">      <span class="keyword">this</span>.$emit(<span class="string">'getCData'</span>,val)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line">    </span><br><span class="line"><span class="keyword">var</span> app=<span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el:<span class="string">'#app'</span>,</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;A /&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><ol><li>组件A 监听 组件B的 getChildData 事件，监听组件C的getCData事件,向B传递了props message,还想向C传递messagec 于是先将messagec通过props的形式传递给组件B</li><li>组件B 向A派发了getChildData事件，<strong>利用props只接收了message这个值</strong>,并没有接收messagec！！<strong>这点很重要</strong>，如果A组件的messagec属性需要向C组件传递，一定不能用props去接收，这样messagec才能挂载到组件B的<code>$attr</code>上,之后利用v-bind将$attr传递给C组件，并通过在C组件上监听$listener将A传递过来的非原生事件监听方法绑定到C上用来监听C组件的同类事件。</li></ol><p><strong>用$emit props实现相同的功能</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'B'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;input type="text" v-model="mymessage" @input="passData(mymessage)"&gt; </span></span><br><span class="line"><span class="string">      &lt;!-- C组件中能直接触发 getCData 的原因在于：B组件调用 C组件时，使用 v-on 绑定了 $listeners 属性 --&gt;</span></span><br><span class="line"><span class="string">      &lt;!-- 通过v-bind 绑定 $attrs 属性，C组件可以直接获取到 A组件中传递下来的 props（除了 B组件中 props声明的） --&gt;</span></span><br><span class="line"><span class="string">      &lt;C v-bind="$attrs" v-on="$listeners"&gt;&lt;/C&gt;</span></span><br><span class="line"><span class="string">      以上写法等效于</span></span><br><span class="line"><span class="string">      &lt;C :messagec="$attrs.messagec" @getCData="$listeners.getCData"&gt;&lt;/C&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  props: [<span class="string">'message'</span>],</span><br><span class="line">  data()&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      mymessage: <span class="keyword">this</span>.message</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    passData(val)&#123;</span><br><span class="line">      <span class="comment">//触发父组件中的事件</span></span><br><span class="line">      <span class="keyword">this</span>.$emit(<span class="string">'getChildData'</span>, val)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">Vue.component(<span class="string">'C'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;input type="text" v-model="messagec" @input="passCData($attrs.messagec)"&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    props: &#123;</span><br><span class="line">        messagec:<span class="string">''</span></span><br><span class="line">    &#125;,</span><br><span class="line">    passCData(val) &#123;</span><br><span class="line">      <span class="comment">// 触发父组件A中的事件</span></span><br><span class="line">      <span class="keyword">this</span>.$emit(<span class="string">'getCData'</span>,val)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><ol start="3"><li>组件C 通过B组件传递过来的$attr属性获取messagec,B通过$listener监听C的事件,再转发给A组件</li></ol><p>上面两种方式都是父子关系，如果是兄弟关系呢？</p><h1 id="EventBus事件总线"><a href="#EventBus事件总线" class="headerlink" title="EventBus事件总线"></a>EventBus事件总线</h1><p>对于非父子关系的组件，如果用前面说到的两种方式需要通过共同的父级作为中间人来进行沟通，非常麻烦。</p><p>可以通过创建一个全局的Vue实例，并使用他的$emit和$on来完成兄弟组件间的通信</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 组件 A</span></span><br><span class="line">Vue.component(<span class="string">'A'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;this is A component!&lt;/p&gt;</span></span><br><span class="line"><span class="string">      &lt;input type="text" v-model="mymessage" @input="passData(mymessage)"&gt; </span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  data() &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      mymessage: <span class="string">'hello brother1'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    passData(val) &#123;</span><br><span class="line">      <span class="comment">//触发全局事件globalEvent</span></span><br><span class="line">      <span class="keyword">this</span>.$EventBus.$emit(<span class="string">'globalEvent'</span>, val)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件 B</span></span><br><span class="line">Vue.component(<span class="string">'B'</span>, &#123;</span><br><span class="line">  template:<span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;this is B component!&lt;/p&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;组件A 传递过来的数据：&#123;&#123;brothermessage&#125;&#125;&lt;/p&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  data() &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      mymessage: <span class="string">'hello brother2'</span>,</span><br><span class="line">      brothermessage: <span class="string">''</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  mounted() &#123;</span><br><span class="line">    <span class="comment">//绑定全局事件globalEvent</span></span><br><span class="line">    <span class="keyword">this</span>.$EventBus.$on(<span class="string">'globalEvent'</span>, (val) =&gt; &#123;</span><br><span class="line">      <span class="keyword">this</span>.brothermessage = val;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">//定义中央事件总线</span></span><br><span class="line"><span class="keyword">const</span> EventBus = <span class="keyword">new</span> Vue();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将中央事件总线赋值到 Vue.prototype 上，这样所有组件都能访问到了</span></span><br><span class="line">Vue.prototype.$EventBus = EventBus;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;A /&gt;</span></span><br><span class="line"><span class="string">      &lt;B /&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>原理很简单，不多赘述</p><h1 id="provide-和-inject"><a href="#provide-和-inject" class="headerlink" title="provide 和 inject"></a>provide 和 inject</h1><p>父组件使用provider暴露需要传递的属性，所有子元素，无论层级有多深，都能通过inject来获取这个属性。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义 parent 组件</span></span><br><span class="line">Vue.component(<span class="string">'parent'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;this is parent component!&lt;/p&gt;</span></span><br><span class="line"><span class="string">      &lt;child&gt;&lt;/child&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  provide: &#123;</span><br><span class="line">    <span class="keyword">for</span>:<span class="string">'test'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      message: <span class="string">'hello'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义 child 组件</span></span><br><span class="line">Vue.component(<span class="string">'child'</span>, &#123;</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;input type="tet" v-model="mymessage"&gt; </span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span>,</span><br><span class="line">  inject: [<span class="string">'for'</span>],	<span class="comment">// 得到父组件传递过来的数据</span></span><br><span class="line">  data()&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      mymessage: <span class="keyword">this</span>.for</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;parent /&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/Vue/">Vue</a></div>  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-09-07  <a class="commentCountImg" href="/2020/09/07/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91vue%E5%85%A8%E5%B1%80%E5%BC%B9%E7%AA%97%E7%BB%84%E4%BB%B6%E5%AE%9E%E7%8E%B0/#comment-container"><span class="display-none-class">2286e46bc041a556a68b3be6a19f4ab4</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="2286e46bc041a556a68b3be6a19f4ab4">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>2 分钟  <i class="fas fa-pencil-alt"> </i>0.4 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/09/07/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91vue%E5%85%A8%E5%B1%80%E5%BC%B9%E7%AA%97%E7%BB%84%E4%BB%B6%E5%AE%9E%E7%8E%B0/">【前端】vue全局弹窗组件实现</a></h1><div class="content"><h1 id="主要内容"><a href="#主要内容" class="headerlink" title="主要内容"></a>主要内容</h1><p>弹窗组件的设计和实现</p><h2 id="实现弹窗组件"><a href="#实现弹窗组件" class="headerlink" title="实现弹窗组件"></a>实现弹窗组件</h2><p>弹窗这类组件的特点是他们在当前vue实力之外独立存在，通常挂载于body; 他们是通过js动态创建的，不需要再任何组件中设声明以element为例子</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$message(&#123;</span><br><span class="line">    title: <span class="string">'性感前端在线炒粉'</span>,</span><br><span class="line">    message: <span class="string">'提示信息'</span>,</span><br><span class="line">    duration: <span class="number">1000</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><strong>实现</strong></p><ol><li>先写一个tiptop.vue文件，使用fixed布局，z-index使它永远在最上层</li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"box"</span> <span class="attr">v-if</span>=<span class="string">"isShow"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">h3</span>&gt;</span>&#123;&#123;title&#125;&#125;<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">p</span> <span class="attr">class</span>=<span class="string">"box-content"</span>&gt;</span>&#123;&#123;message&#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line">        props: &#123;</span><br><span class="line">            title: &#123;</span><br><span class="line"><span class="javascript">                type: <span class="built_in">String</span>,</span></span><br><span class="line"><span class="actionscript">                <span class="keyword">default</span>: <span class="string">""</span></span></span><br><span class="line">            &#125;,</span><br><span class="line">            message: &#123;</span><br><span class="line"><span class="javascript">                type: <span class="built_in">String</span>,</span></span><br><span class="line"><span class="actionscript">                <span class="keyword">default</span>: <span class="string">""</span></span></span><br><span class="line">            &#125;,</span><br><span class="line">            duration: &#123;</span><br><span class="line"><span class="javascript">                type: <span class="built_in">Number</span>,</span></span><br><span class="line"><span class="actionscript">                <span class="keyword">default</span>: <span class="number">1000</span></span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        data() &#123;</span><br><span class="line"><span class="actionscript">            <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="actionscript">                isShow: <span class="literal">false</span>,</span></span><br><span class="line"><span class="actionscript">                timer: <span class="literal">null</span></span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;,</span><br><span class="line">        methods: &#123;</span><br><span class="line">            show() &#123;</span><br><span class="line"><span class="actionscript">              <span class="keyword">this</span>.isShow = <span class="literal">true</span>;</span></span><br><span class="line"><span class="actionscript">              timer = setTimeout(<span class="keyword">this</span>.hide, <span class="keyword">this</span>.duration);</span></span><br><span class="line">            &#125;,</span><br><span class="line">            hide() &#123;</span><br><span class="line"><span class="actionscript">                <span class="keyword">this</span>.isShow = <span class="literal">false</span>;</span></span><br><span class="line">                timer &amp;&amp; clearTimeout(timer)</span><br><span class="line"><span class="actionscript">                <span class="keyword">this</span>.remove(); <span class="comment">// 这个方法后面直接挂载到实例上，这里不定义</span></span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span></span><br><span class="line"><span class="css">    <span class="selector-class">.box</span> &#123;</span></span><br><span class="line">        position: fixed;</span><br><span class="line">        width: 100%;</span><br><span class="line">        top: 16px;</span><br><span class="line">        left: 0;</span><br><span class="line">        text-align: center;</span><br><span class="line">        pointer-events: none;</span><br><span class="line">        z-index: 999;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="css">    <span class="selector-class">.box-content</span> &#123;</span></span><br><span class="line">        width: 200px;</span><br><span class="line">        margin: 10px auto;</span><br><span class="line">        font-size: 14px;</span><br><span class="line">        border: blue 3px solid;</span><br><span class="line">        padding: 8px 16px;</span><br><span class="line"><span class="css">        <span class="selector-tag">background</span>: <span class="selector-id">#fff</span>;</span></span><br><span class="line">        border-radius: 3px;</span><br><span class="line">        margin-bottom: 8px;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure><ol start="2"><li>创建一个方法用来在外部调用这个组件</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> tiptop <span class="keyword">from</span> <span class="string">'./tiptop'</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_tipTop</span> (<span class="params">props</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> _vm = <span class="keyword">new</span> vue(&#123;</span><br><span class="line">        render(h) &#123;</span><br><span class="line">            <span class="comment">// 调用刚刚引入的组件，传入参数</span></span><br><span class="line">            <span class="keyword">return</span> h(tiptop,&#123; props &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 执行挂载函数，但未设置挂载目标，表示只执行了初始化的工作</span></span><br><span class="line">    &#125;).$mount()</span><br><span class="line">    <span class="comment">// 通过$el获取到真实的element并且挂载在body上</span></span><br><span class="line">    <span class="built_in">document</span>.body.appendChild(vm.$el)</span><br><span class="line">    <span class="comment">// 获取组件实例，挂载remove方法</span></span><br><span class="line">    <span class="keyword">const</span> comp = vm.$children[<span class="number">0</span>]</span><br><span class="line">    comp.remove = <span class="function"><span class="params">()</span>=&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">document</span>.bodu.removeChild(vm.$el);</span><br><span class="line">        vm.$destroy()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="index-category-tag">  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-09-05  <a class="commentCountImg" href="/2020/09/05/%E3%80%90linux-%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91%E3%80%91%E8%A7%A3%E5%86%B3google%E6%9C%BA%E5%99%A8%E4%BA%BA%E9%AA%8C%E8%AF%81%E9%97%AE%E9%A2%98/#comment-container"><span class="display-none-class">b7484a45eb6d845d61e7a147e179b232</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="b7484a45eb6d845d61e7a147e179b232">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>8 分钟  <i class="fas fa-pencil-alt"> </i>1.2 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/09/05/%E3%80%90linux-%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91%E3%80%91%E8%A7%A3%E5%86%B3google%E6%9C%BA%E5%99%A8%E4%BA%BA%E9%AA%8C%E8%AF%81%E9%97%AE%E9%A2%98/">【linux+科学上网】解决google机器人验证问题</a></h1><div class="content"><h1 id="解决VPS多次使用google时，出现的机器人验证"><a href="#解决VPS多次使用google时，出现的机器人验证" class="headerlink" title="解决VPS多次使用google时，出现的机器人验证"></a>解决VPS多次使用google时，出现的机器人验证</h1><p><strong>原理</strong></p><p>利用内网的某一台服务器，或公网的一台服务器做跳板，将所有的请求集中到一台机器上，再访问境外服务器，可以大大减少被谷歌机器人验证的频率。所以，在看本文之前，需要你已经部署了一台trojan服务端具体内容可以看这篇文章<br><a href="https://wxperia.com/2020/02/18/trojan%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8/">trojan的安装与使用</a></p><h1 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h1><p><strong>工具</strong></p><p>【注意】**<em>根据自己的系统下载不同的版本**</em></p><ul><li><p>trojan-go: <a href="https://github.com/p4gefau1t/trojan-go/releases">点击下载</a></p><p>简介：使用Go实现的完整Trojan代理，与Trojan协议以及Trojan版本的配置文件格式兼容。安全，轻巧，易用。</p></li><li><p>v2ray: <a href="https://github.com/v2ray/v2ray-core/releases/tag/v4.27.5">点击下载</a></p><p>简介：V2Ray 是一个与 Shadowsocks 类似的代理软件，可以用来科学上网（翻墙）学习国外先进科学技术。</p><ul><li><a href="https://github.com/v2ray/v2ray-core/releases/download/v4.27.5/v2ray-windows-64.zip">windows v2ray客户端</a></li><li><a href="https://github.com/2dust/v2rayNG/releases/download/1.3.3/v2rayNG_1.3.3.apk">android v2ray客户端</a></li><li>ios 需要自己找，爱莫能助</li></ul></li><li><p>xshell</p></li><li><p>lrzsz</p><p>简介：xshell文件上传工具</p></li></ul><p><strong>环境</strong></p><ul><li>ubuntu 20.04 mate arm64 (树莓派4B)</li></ul><h1 id="安装trojan-go"><a href="#安装trojan-go" class="headerlink" title="安装trojan-go"></a>安装trojan-go</h1><p>将下载好的包上传到服务器/usr/local文件夹下，并解压</p><p>安装上传文件的工具</p><blockquote><p>sudo apt-get install lrzsz</p></blockquote><p>进入需要上传的目录，用鼠标将下载好的包上传上去</p><blockquote><p>cd /usr/local</p></blockquote><blockquote><p>tar -xvf trojan-go-linux-arm.zip ./trojan</p></blockquote><p>使用<a href="https://wxperia.com/2020/02/18/trojan%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8/">trojan的安装与使用</a>中，最终下载下来的trojan客户端中的config.json与fullchain.cer上传到服务器替换服务器/usr/local/trojan中的对应文件</p><p><code>config.json</code></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="attr">"run_type"</span>: <span class="string">"client"</span>,</span><br><span class="line">    <span class="attr">"local_addr"</span>: <span class="string">"127.0.0.1"</span>,</span><br><span class="line">    <span class="attr">"local_port"</span>: <span class="number">1080</span>,</span><br><span class="line">    <span class="attr">"remote_addr"</span>: <span class="string">"www.example.com"</span>,</span><br><span class="line">    <span class="attr">"remote_port"</span>: <span class="number">443</span>,</span><br><span class="line">    <span class="attr">"password"</span>: [</span><br><span class="line">        <span class="string">"your_password"</span></span><br><span class="line">    ],</span><br><span class="line">    <span class="attr">"log_level"</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="attr">"ssl"</span>: &#123;</span><br><span class="line">        <span class="attr">"verify"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">"verify_hostname"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">"cert"</span>: <span class="string">"fullchain.cer"</span>,</span><br><span class="line">        <span class="attr">"cipher_tls13"</span>:<span class="string">"TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384"</span>,</span><br><span class="line"><span class="attr">"sni"</span>: <span class="string">""</span>,</span><br><span class="line">        <span class="attr">"alpn"</span>: [</span><br><span class="line">            <span class="string">"h2"</span>,</span><br><span class="line">            <span class="string">"http/1.1"</span></span><br><span class="line">        ],</span><br><span class="line">        <span class="attr">"reuse_session"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">"session_ticket"</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="attr">"curves"</span>: <span class="string">""</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">"tcp"</span>: &#123;</span><br><span class="line">        <span class="attr">"no_delay"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">"keep_alive"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">"fast_open"</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="attr">"fast_open_qlen"</span>: <span class="number">20</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>cd /usr/local/trojan</p></blockquote><p>开启trojan-go</p><blockquote><p>./trojan-go -config ./config.json</p></blockquote><p>如果没有报错的话，就使用systemctl 添加自启动</p><blockquote><p>vim trojan.service</p></blockquote><p>将下面这部分内容复制进去</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Unit]</span></span><br><span class="line"><span class="attr">Description</span>=trojan-go</span><br><span class="line"><span class="attr">After</span>=network.target</span><br><span class="line"><span class="section">[Service]</span></span><br><span class="line"><span class="attr">Type</span>=simple</span><br><span class="line"><span class="attr">StandardError</span>=journal</span><br><span class="line"><span class="attr">User</span>=nobody</span><br><span class="line"><span class="attr">AmbientCapabilities</span>=CAP_NET_BIND_SERVICE</span><br><span class="line"><span class="attr">ExecStart</span>=/usr/local/trojan/trojan-go -config /usr/local/trojan/config.json</span><br><span class="line"><span class="attr">ExecReload</span>=/bin/kill -HUP <span class="variable">$MAINPID</span></span><br><span class="line"><span class="attr">Restart</span>=<span class="literal">on</span>-failure</span><br><span class="line"><span class="attr">RestartSec</span>=<span class="number">3</span>s</span><br><span class="line"></span><br><span class="line"><span class="section">[Install]</span></span><br><span class="line"><span class="attr">WantedBy</span>=multi-user.target</span><br></pre></td></tr></table></figure><p>注册服务</p><blockquote><p>mv trojan.service /lib/systemd/system</p></blockquote><blockquote><p>systemctl start trojan</p></blockquote><p>查看运行状态</p><blockquote><p>systemctl status trojan</p></blockquote><p>出现下面这样的结果就算运行成功了</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">● trojan.service - trojan-go</span><br><span class="line">     Loaded: loaded (&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;trojan.service; enabled; vendor preset: enabled)</span><br><span class="line">     Active: active (running) since Sat 2020-09-05 13:36:01 CST; 52min ago</span><br><span class="line">   Main PID: 69188 (trojan-go)</span><br><span class="line">      Tasks: 7 (limit: 4206)</span><br><span class="line">     CGroup: &#x2F;system.slice&#x2F;trojan.service</span><br><span class="line">             └─69188 &#x2F;usr&#x2F;local&#x2F;trojan&#x2F;trojan-go -config &#x2F;usr&#x2F;local&#x2F;trojan&#x2F;config.json</span><br></pre></td></tr></table></figure><h1 id="安装v2ray"><a href="#安装v2ray" class="headerlink" title="安装v2ray"></a>安装v2ray</h1><p>进入刚刚上传包的目录</p><blockquote><p>cd /usr/local</p></blockquote><p>解压到 v2ray 目录</p><blockquote><p>unzip v2ray-linux-arm64-v8a.zip -d ./v2ray</p></blockquote><p>进入v2ray 修改config文件</p><blockquote><p>cd /usr/local/v2ray</p></blockquote><blockquote><p>vim config.json</p></blockquote><p>将里面的内容删除替换成以下内容 <strong>【注意】需要先删掉注释！！！！！！</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"policy"</span>: &#123;</span><br><span class="line">    <span class="attr">"system"</span>: &#123;</span><br><span class="line">      <span class="attr">"statsInboundUplink"</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="attr">"statsInboundDownlink"</span>: <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">"log"</span>: &#123;</span><br><span class="line">    <span class="attr">"access"</span>: <span class="string">""</span>,</span><br><span class="line">    <span class="attr">"error"</span>: <span class="string">""</span>,</span><br><span class="line">    <span class="attr">"loglevel"</span>: <span class="string">"warning"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// 本地代理端口1081,待会本地填的就是这个端口</span></span><br><span class="line">  <span class="attr">"inbounds"</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"tag"</span>: <span class="string">"proxy"</span>,</span><br><span class="line">      <span class="attr">"port"</span>: <span class="number">1081</span>,</span><br><span class="line">      <span class="attr">"listen"</span>: <span class="string">"0.0.0.0"</span>,</span><br><span class="line">      <span class="attr">"protocol"</span>: <span class="string">"socks"</span>,</span><br><span class="line">      <span class="attr">"sniffing"</span>: &#123;</span><br><span class="line">        <span class="attr">"enabled"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">"destOverride"</span>: [</span><br><span class="line">          <span class="string">"http"</span>,</span><br><span class="line">          <span class="string">"tls"</span></span><br><span class="line">        ]</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"settings"</span>: &#123;</span><br><span class="line">        <span class="attr">"auth"</span>: <span class="string">"noauth"</span>,</span><br><span class="line">        <span class="attr">"udp"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">"ip"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"address"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"clients"</span>: <span class="literal">null</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"streamSettings"</span>: <span class="literal">null</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"tag"</span>: <span class="string">"api"</span>,</span><br><span class="line">      <span class="attr">"port"</span>: <span class="number">50262</span>,</span><br><span class="line">      <span class="attr">"listen"</span>: <span class="string">"127.0.0.1"</span>,</span><br><span class="line">      <span class="attr">"protocol"</span>: <span class="string">"dokodemo-door"</span>,</span><br><span class="line">      <span class="attr">"sniffing"</span>: <span class="literal">null</span>,</span><br><span class="line">      <span class="attr">"settings"</span>: &#123;</span><br><span class="line">        <span class="attr">"auth"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"udp"</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="attr">"ip"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"address"</span>: <span class="string">"127.0.0.1"</span>,</span><br><span class="line">        <span class="attr">"clients"</span>: <span class="literal">null</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"streamSettings"</span>: <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  <span class="comment">// 连接trojan-go的端口1080</span></span><br><span class="line">  <span class="attr">"outbounds"</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"tag"</span>: <span class="string">"proxy"</span>,</span><br><span class="line">      <span class="attr">"protocol"</span>: <span class="string">"socks"</span>,</span><br><span class="line">      <span class="attr">"settings"</span>: &#123;</span><br><span class="line">        <span class="attr">"vnext"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"servers"</span>: [</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="attr">"email"</span>: <span class="literal">null</span>,</span><br><span class="line">            <span class="attr">"address"</span>: <span class="string">"127.0.0.1"</span>,</span><br><span class="line">            <span class="attr">"method"</span>: <span class="literal">null</span>,</span><br><span class="line">            <span class="attr">"ota"</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">"password"</span>: <span class="literal">null</span>,</span><br><span class="line">            <span class="attr">"port"</span>: <span class="number">1080</span>,</span><br><span class="line">            <span class="attr">"level"</span>: <span class="number">1</span>,</span><br><span class="line">            <span class="attr">"users"</span>: <span class="literal">null</span></span><br><span class="line">          &#125;</span><br><span class="line">        ],</span><br><span class="line">        <span class="attr">"response"</span>: <span class="literal">null</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"streamSettings"</span>: &#123;</span><br><span class="line">        <span class="attr">"network"</span>: <span class="string">"tcp"</span>,</span><br><span class="line">        <span class="attr">"security"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"tlsSettings"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"tcpSettings"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"kcpSettings"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"wsSettings"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"httpSettings"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"quicSettings"</span>: <span class="literal">null</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"mux"</span>: &#123;</span><br><span class="line">        <span class="attr">"enabled"</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="attr">"concurrency"</span>: <span class="number">-1</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"tag"</span>: <span class="string">"direct"</span>,</span><br><span class="line">      <span class="attr">"protocol"</span>: <span class="string">"freedom"</span>,</span><br><span class="line">      <span class="attr">"settings"</span>: &#123;</span><br><span class="line">        <span class="attr">"vnext"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"servers"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"response"</span>: <span class="literal">null</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"streamSettings"</span>: <span class="literal">null</span>,</span><br><span class="line">      <span class="attr">"mux"</span>: <span class="literal">null</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"tag"</span>: <span class="string">"block"</span>,</span><br><span class="line">      <span class="attr">"protocol"</span>: <span class="string">"blackhole"</span>,</span><br><span class="line">      <span class="attr">"settings"</span>: &#123;</span><br><span class="line">        <span class="attr">"vnext"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"servers"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"response"</span>: &#123;</span><br><span class="line">          <span class="attr">"type"</span>: <span class="string">"http"</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"streamSettings"</span>: <span class="literal">null</span>,</span><br><span class="line">      <span class="attr">"mux"</span>: <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">"stats"</span>: &#123;&#125;,</span><br><span class="line">  <span class="attr">"api"</span>: &#123;</span><br><span class="line">    <span class="attr">"tag"</span>: <span class="string">"api"</span>,</span><br><span class="line">    <span class="attr">"services"</span>: [</span><br><span class="line">      <span class="string">"StatsService"</span></span><br><span class="line">    ]</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">"dns"</span>: <span class="literal">null</span>,</span><br><span class="line">  <span class="attr">"routing"</span>: &#123;</span><br><span class="line">    <span class="attr">"domainStrategy"</span>: <span class="string">"IPIfNonMatch"</span>,</span><br><span class="line">    <span class="attr">"rules"</span>: [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">"type"</span>: <span class="string">"field"</span>,</span><br><span class="line">        <span class="attr">"port"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"inboundTag"</span>: [</span><br><span class="line">          <span class="string">"api"</span></span><br><span class="line">        ],</span><br><span class="line">        <span class="attr">"outboundTag"</span>: <span class="string">"api"</span>,</span><br><span class="line">        <span class="attr">"ip"</span>: <span class="literal">null</span>,</span><br><span class="line">        <span class="attr">"domain"</span>: <span class="literal">null</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>启动v2ray</p><blockquote><p>/usr/local/v2ray/v2ray -c /usr/local/v2ray/config.json</p></blockquote><p><strong>注册服务</strong></p><p>v2ray 自带service文件，就在v2ray下的systemd/system下</p><blockquote><p>vim /usr/local/v2ray/systemd/system/v2ray.servcie</p></blockquote><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Unit]</span></span><br><span class="line"><span class="attr">Description</span>=V2Ray Service</span><br><span class="line"><span class="attr">Documentation</span>=https://www.v2fly.org/</span><br><span class="line"><span class="attr">After</span>=network.target nss-lookup.target</span><br><span class="line"></span><br><span class="line"><span class="section">[Service]</span></span><br><span class="line"><span class="attr">User</span>=nobody</span><br><span class="line"><span class="attr">CapabilityBoundingSet</span>=CAP_NET_ADMIN CAP_NET_BIND_SERVICE</span><br><span class="line"><span class="attr">AmbientCapabilities</span>=CAP_NET_ADMIN CAP_NET_BIND_SERVICE</span><br><span class="line"><span class="attr">NoNewPrivileges</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">ExecStart</span>=/usr/local/v2ray/v2ray -config /usr/local/v2ray/config.json</span><br><span class="line"><span class="attr">Restart</span>=<span class="literal">on</span>-failure</span><br><span class="line"></span><br><span class="line"><span class="section">[Install]</span></span><br><span class="line"><span class="attr">WantedBy</span>=multi-user.target</span><br></pre></td></tr></table></figure><p>注册服务</p><blockquote><p>mv /usr/local/v2ray/systemd/system/v2ray.servcie /lib/systemd/system</p></blockquote><p>启动v2ray</p><blockquote><p>systemctl start v2ray</p></blockquote><p>给两个服务开启自启动</p><blockquote><p>systemctl enable trojan</p></blockquote><blockquote><p>systemctl enable v2ray</p></blockquote><p>配置window下的v2ray</p><p><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20200905145147.png" alt="配置v2ray"></p><p>安心上网</p><p><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20200905145729.png" alt="配置v2ray"></p></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91-linux/">科学上网 linux</a></div>  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-08-31  <a class="commentCountImg" href="/2020/08/31/%E3%80%90linux%E3%80%91github-webhook%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2/#comment-container"><span class="display-none-class">a57632ad57c4f7fbf94234dc50c231b0</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="a57632ad57c4f7fbf94234dc50c231b0">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>4 分钟  <i class="fas fa-pencil-alt"> </i>0.7 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/08/31/%E3%80%90linux%E3%80%91github-webhook%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2/">【linux】github-webhooks实现自动部署</a></h1><div class="content"><h1 id="涉及知识点"><a href="#涉及知识点" class="headerlink" title="涉及知识点"></a>涉及知识点</h1><ul><li>nodejs</li><li>github</li><li>linux shell</li><li>nginx</li><li>pm2</li></ul><h1 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h1><p>利用<code>webhook</code>通知服务器，仓库有<code>push</code>或者其他操作，服务得到通知后利用<code>sh</code>脚本拉取最新的代码并完成部署</p><h1 id="新建一个privte库"><a href="#新建一个privte库" class="headerlink" title="新建一个privte库"></a>新建一个privte库</h1><p>因为<code>webhook</code>需要一个<code>secret</code>字段来验证身份，所以需要建立<code>private</code>库保证安全！</p><p>将仓库<code>clone</code>到本地，进入到项目目录下执行：</p><blockquote><p>npm init –y</p></blockquote><blockquote><p>npm i github-webhook-handler</p></blockquote><p>新建一个<code>auto_build.js</code>文件</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">'http'</span>)</span><br><span class="line"><span class="keyword">var</span> spawn = <span class="built_in">require</span>(<span class="string">'child_process'</span>).spawn</span><br><span class="line"><span class="keyword">var</span> createHandler = <span class="built_in">require</span>(<span class="string">'github-webhook-handler'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 下面填写的myscrect跟github webhooks配置一样，下一步会说；path是我们访问的路径</span></span><br><span class="line"><span class="comment">// secret 对应webhook里的secret字段 path就是接口访问的地址</span></span><br><span class="line"><span class="keyword">var</span> handler = createHandler(&#123; <span class="attr">path</span>: <span class="string">'/auto_build'</span>, <span class="attr">secret</span>: <span class="string">'这里写你的secret后面用得到！'</span> &#125;)</span><br><span class="line"></span><br><span class="line">http.createServer(<span class="function"><span class="keyword">function</span> (<span class="params">req, res</span>) </span>&#123;</span><br><span class="line">    handler(req, res, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        res.statusCode = <span class="number">404</span></span><br><span class="line">        res.end(<span class="string">'no such location'</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'listen on 6666'</span>)</span><br><span class="line">&#125;).listen(<span class="number">6666</span>)</span><br><span class="line"></span><br><span class="line">handler.on(<span class="string">'error'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">err</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.error(<span class="string">'Error:'</span>, err.message)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 监听到push事件的时候执行我们的自动化脚本</span></span><br><span class="line">handler.on(<span class="string">'push'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">event</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Received a push event for %s to %s'</span>,</span><br><span class="line">        event.payload.repository.name,</span><br><span class="line">        event.payload.ref)</span><br><span class="line">    <span class="comment">// 这个路径就是需要执行的sh脚本的路径</span></span><br><span class="line">    runCommand(<span class="string">'sh'</span>, [<span class="string">'./auto_build.sh'</span>], <span class="function"><span class="keyword">function</span> (<span class="params">txt</span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(txt)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">runCommand</span> (<span class="params">cmd, args, callback</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> child = spawn(cmd, args)</span><br><span class="line">    <span class="keyword">var</span> resp = <span class="string">''</span></span><br><span class="line">    child.stdout.on(<span class="string">'data'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">buffer</span>) </span>&#123; resp += buffer.toString() &#125;)</span><br><span class="line">    child.stdout.on(<span class="string">'end'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123; callback(resp) &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 由于我们不需要监听issues，所以下面代码注释掉</span></span><br><span class="line"><span class="comment">//  handler.on('issues', function (event) &#123;</span></span><br><span class="line"><span class="comment">//    console.log('Received an issue event for %s action=%s: #%d %s',</span></span><br><span class="line"><span class="comment">//      event.payload.repository.name,</span></span><br><span class="line"><span class="comment">//      event.payload.action,</span></span><br><span class="line"><span class="comment">//      event.payload.issue.number,</span></span><br><span class="line"><span class="comment">//      event.payload.issue.title)</span></span><br><span class="line"><span class="comment">// &#125;);</span></span><br></pre></td></tr></table></figure><p>新建一个<code>auto_build.sh</code>文件，写入以下内容</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#! /bin/bash</span></span><br><span class="line"><span class="comment"># 项目地址，注意要是绝对路径，防止不必要的错误</span></span><br><span class="line">SITE_PATH=<span class="string">'project-path'</span></span><br><span class="line">USER=<span class="string">'admin'</span></span><br><span class="line">USERGROUP=<span class="string">'admin'</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> <span class="variable">$SITE_PATH</span></span><br><span class="line">git reset --hard origin/master</span><br><span class="line">git clean -f</span><br><span class="line">git pull</span><br><span class="line">git checkout master</span><br><span class="line">cnpm run build</span><br><span class="line">chown -R <span class="variable">$USER</span>:<span class="variable">$USERGROUP</span> <span class="variable">$SITE_PATH</span></span><br></pre></td></tr></table></figure><p>将这个项目<code>push</code>到<code>github</code>中<strong>【注意】（这个操作需要你先将服务器的<code>sshkey</code>添加到<code>github</code>）</strong>，或者直接上传到你的服务器，使用pm2启动</p><p>如果没有<code>pm2</code>请先安装</p><blockquote><p>npm install -g pm2</p></blockquote><blockquote><p>pm2 start auto_build.js</p></blockquote><h1 id="nginx反向代理"><a href="#nginx反向代理" class="headerlink" title="nginx反向代理"></a>nginx反向代理</h1><p><code>nginx.conf</code> 添加以下配置</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">location /auto_build &#123;</span><br><span class="line">     proxy_pass http://127.0.0.1:6666;</span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure><h1 id="github-webhooks-配置"><a href="#github-webhooks-配置" class="headerlink" title="github webhooks 配置"></a>github webhooks 配置</h1><p>进入需要配置自动部署的库，点击最左边的<code>settings</code>选项，</p><ul><li><code>Payload URL</code> 接口访问地址</li><li><code>Content type</code> 选json</li><li><code>secret</code> 就是之前写的 <code>secret</code>两个要保持一致</li></ul><p><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20200831230831.png" alt="webhook配置"></p><h1 id="测试push"><a href="#测试push" class="headerlink" title="测试push"></a>测试push</h1><p>不出问题的话，现在仓库的push能被监听了</p><p><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img/20200831231044.png" alt="测试结果"></p></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/linux/">linux</a></div>  <hr></div></article></div><nav class="pagination is-centered mt-4" role="navigation" aria-label="pagination"><div class="pagination-previous is-invisible is-hidden-mobile"><a href="/page/0/">上一页</a></div><div class="pagination-next"><a href="/page/2/">下一页</a></div><ul class="pagination-list is-hidden-mobile"><li><a class="pagination-link is-current" href="/">1</a></li><li><a class="pagination-link" href="/page/2/">2</a></li><li><span class="pagination-ellipsis">&hellip;</span></li><li><a class="pagination-link" href="/page/5/">5</a></li></ul></nav></div><div class="column column-left is-4-tablet is-4-desktop is-3-widescreen order-1 is-sticky"><div class="card widget"><div class="card-content"><nav class="level"><div class="level-item has-text-centered flex-shrink-1"><div><figure class="image is-128x128 mx-auto mb-2"><img class="is-rounded" src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png" alt="Wxperia🚀"></figure><p class="title is-size-4 is-block line-height-inherit">Wxperia🚀</p><p class="is-size-6 is-block">江湖中迷走</p><p class="is-size-6 is-flex justify-content-center"><i class="fas fa-map-marker-alt mr-1"></i><span>广州🍵</span></p></div></div></nav><nav class="level is-mobile"><div class="level-item has-text-centered is-marginless"><div><p class="heading">文章</p><a href="/archives"><p class="title">46</p></a></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">分类</p><a href="/categories"><p class="title">24</p></a></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">标签</p><a href="/tags"><p class="title">35</p></a></div></div></nav><div class="level"><a class="level-item button is-primary is-rounded" href="/" target="_blank" rel="noopener">关注我</a></div><div class="level is-mobile"><a class="level-item button is-transparent is-white is-marginless" target="_blank" rel="noopener" title="Github" href="https://github.com/Wxperia"><i class="fab fa-github"></i></a><a class="level-item button is-transparent is-white is-marginless" target="_blank" rel="noopener" title="Weibo" href="https://weibo.com/u/3050419984"><i class="fab fa-weibo"></i></a><a class="level-item button is-transparent is-white is-marginless" target="_blank" rel="noopener" title="Email" href="/914827352@qq.com"><i class="fa fa-envelope"></i></a></div><div><hr><p id="hitokoto">:D 一言句子获取中...</p><script type="text/javascript" defer>function getYiyan(){$.getJSON("https://v1.hitokoto.cn/",function(o){o&&($("#hitokoto").html(""),$("#hitokoto").append("<strong style='color: #3273dc;'>"+o.hitokoto+"</strong><p>来源《"+o.from+"》</p><p>提供者-"+o.creator+"</p>"))})}$(function(){getYiyan(),$("#hitokoto").click(function(){getYiyan()})})</script></div></div></div><div class="column-right-shadow is-hidden-widescreen"></div></div><div class="column column-right is-4-tablet is-4-desktop is-3-widescreen is-hidden-touch is-hidden-desktop-only order-3"><div class="card widget"><div class="card-content"><h3 class="menu-label">最新文章</h3><article class="media"><div class="media-content size-small"><p><time datetime="2020-12-29T06:41:57.000Z">2020-12-29</time></p><p class="title is-6"><a class="link-muted" href="/2020/12/29/%E3%80%90vue%E3%80%91%E8%A7%A3%E8%80%A6%E6%A8%A1%E5%9D%97%E4%B9%8B%E9%97%B4%E7%9A%84%E8%AF%AD%E8%A8%80%E6%96%87%E4%BB%B6/">【vue】解耦模块之间的语言文件</a></p><p class="is-uppercase"></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-12-28T01:46:47.000Z">2020-12-28</time></p><p class="title is-6"><a class="link-muted" href="/2020/12/28/%E3%80%90vue%E3%80%91%E6%97%A0%E7%BC%9Dtoken%E5%88%B7%E6%96%B0/">【vue】无缝token刷新</a></p><p class="is-uppercase"><i class="fas fa-folder-open has-text-grey"> </i><a class="link-muted" href="/categories/axios-token-refresh-token/">axios token refresh token</a></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-12-24T15:56:05.000Z">2020-12-24</time></p><p class="title is-6"><a class="link-muted" href="/2020/12/24/HTML%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/">HTML理论知识</a></p><p class="is-uppercase"></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-11-21T15:32:53.000Z">2020-11-21</time></p><p class="title is-6"><a class="link-muted" href="/2020/11/21/%E7%8A%80%E7%9A%AE%E6%BC%86%E5%99%A8%E7%9A%84%E4%B8%80%E8%88%AC%E5%88%B6%E4%BD%9C%E6%AD%A5%E9%AA%A4/">【花活】犀皮漆器的一般制作步骤</a></p><p class="is-uppercase"><i class="fas fa-folder-open has-text-grey"> </i><a class="link-muted" href="/categories/%E6%BC%86%E5%99%A8/">漆器</a></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-11-01T04:08:22.000Z">2020-11-01</time></p><p class="title is-6"><a class="link-muted" href="/2020/11/01/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91vue%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E5%AE%9E%E7%8E%B0-1/">【前端】vue权限管理</a></p><p class="is-uppercase"></p></div></article></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">分类</h3><ul class="menu-list"><li><a class="level is-mobile is-marginless" href="/categories/Linux/"><span class="level-start"><span class="level-item">Linux</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/Tools/"><span class="level-start"><span class="level-item">Tools</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/Typescript/"><span class="level-start"><span class="level-item">Typescript</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/Vue/"><span class="level-start"><span class="level-item">Vue</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/axios-token-refresh-token/"><span class="level-start"><span class="level-item">axios token refresh token</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/css/"><span class="level-start"><span class="level-item">css</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/docker/"><span class="level-start"><span class="level-item">docker</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/hexo/"><span class="level-start"><span class="level-item">hexo</span></span><span class="level-end"><span class="level-item tag">4</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/hexo-Travis-github-action/"><span class="level-start"><span class="level-item">hexo Travis github-action</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/jQuery/"><span class="level-start"><span class="level-item">jQuery</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><a class="level is-mobile is-marginless" href="/categories/"><span class="level-start"><span class="level-item">查看全部&gt;&gt;</span></span></a></ul></div></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">归档</h3><ul class="menu-list"><li><a class="level is-mobile is-marginless" href="/archives/2020/12/"><span class="level-start"><span class="level-item">十二月 2020</span></span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/11/"><span class="level-start"><span class="level-item">十一月 2020</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/09/"><span class="level-start"><span class="level-item">九月 2020</span></span><span class="level-end"><span class="level-item tag">4</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/08/"><span class="level-start"><span class="level-item">八月 2020</span></span><span class="level-end"><span class="level-item tag">7</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/05/"><span class="level-start"><span class="level-item">五月 2020</span></span><span class="level-end"><span class="level-item tag">4</span></span></a></li><a class="level is-mobile is-marginless" href="/archives/"><span class="level-start"><span class="level-item">查看全部&gt;&gt;</span></span></a></ul></div></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">标签</h3><div class="field is-grouped is-grouped-multiline"><div class="control"><a class="tags has-addons" href="/tags/ES6/"><span class="tag">ES6</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/metingJs/"><span class="tag">metingJs</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/JavaScript/"><span class="tag">JavaScript</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/LINUX/"><span class="tag">LINUX</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/OSS/"><span class="tag">OSS</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Typescript/"><span class="tag">Typescript</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/aplayer/"><span class="tag">aplayer</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/cdn/"><span class="tag">cdn</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/es5/"><span class="tag">es5</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/funllscreen/"><span class="tag">funllscreen</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/git/"><span class="tag">git</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/github/"><span class="tag">github</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/github-page/"><span class="tag">github page</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/git%E5%A4%87%E4%BB%BD/"><span class="tag">git备份</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/google/"><span class="tag">google</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/javaScript/"><span class="tag">javaScript</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/markdown/"><span class="tag">markdown</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/tools-%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7/"><span class="tag">+ tools + 实用工具</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/office2010/"><span class="tag">office2010</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/thymeleaft3/"><span class="tag">thymeleaft3</span><span class="tag is-grey-lightest">1</span></a></div></div><div class="field is-grouped is-grouped-multiline"><a class="tags has-addons" href="/tags/"><span class="tag">查看全部&gt;&gt;</span></a></div></div></div></div></div></div></div></section><footer class="footer"><div class="container"><div class="level"><div class="level-start"><a class="footer-logo is-block mb-2" href="/"><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png" alt="谢子乾" height="28"></a><p class="size-small"><span>&copy; 2020 谢子乾</span>    <br><span>© 版权说明：[本网站所有内容均收集于互联网或自己创作,<br>&nbsp;&nbsp;&nbsp;&nbsp;方便于网友与自己学习交流，如有侵权，请<a href="/message" target="_blank">留言</a>，立即处理]<br></span><span><span id="statistic-times">loading...</span><script>function createTime(n){var t=new Date(n);now.setTime(now.getTime()+250),days=(now-t)/1e3/60/60/24,dnum=Math.floor(days),hours=(now-t)/1e3/60/60-24*dnum,hnum=Math.floor(hours),1==String(hnum).length&&(hnum="0"+hnum),minutes=(now-t)/1e3/60-1440*dnum-60*hnum,mnum=Math.floor(minutes),1==String(mnum).length&&(mnum="0"+mnum),seconds=(now-t)/1e3-86400*dnum-3600*hnum-60*mnum,snum=Math.round(seconds),1==String(snum).length&&(snum="0"+snum),document.getElementById("statistic-times").innerHTML="❤️本站自 <strong>"+n.split(" ")[0].replace(/\//g,".")+"</strong> 已运行 <strong>"+dnum+"</strong> 天 <strong>"+hnum+"</strong> 小时 <strong>"+mnum+"</strong> 分 <strong>"+snum+"</strong> 秒！❤️"}var now=new Date;setInterval("createTime('2018/11/11 00:00:00')",250,"")</script><br></span></p><div class="size-small"><span>❤️感谢 <strong><span id="busuanzi_value_site_uv">99+</span></strong> 小伙伴的 <strong><span id="busuanzi_value_site_pv">99+</span></strong> 次光临！❤️</span></div><p></p></div><div class="level-end"><div class="field has-addons"><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Creative Commons" href="https://creativecommons.org/"><i class="fab fa-creative-commons"></i></a></p><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Attribution 4.0 International" href="https://creativecommons.org/licenses/by/4.0/"><i class="fab fa-creative-commons-by"></i></a></p><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Download on GitHub" href="https://github.com/removeif"><i class="fab fa-github"></i></a></p></div><div class="sideMusic" id="myAdlayer"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.10.1/APlayer.min.css" integrity="sha256-uqQQGnDcmRKvhKwc5Vm4XT1GQ2oV6t1U0NR2N9tV+BQ=" crossorigin="anonymous"><script src="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.10.1/APlayer.min.js" integrity="sha256-6Y7CJDaltoeNgk+ZftgCD9jLgmGv4xKUo8nQ0HgAwVo=" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script><meting-js style="width:auto;height:2000px" type="playlist" auto="https://y.qq.com/n/yqq/playlist/7375663759.html#stat=y_new.profile.create_playlist.click&amp;dirid=24" theme="#2980b9" loop autoplay order="list" storagename="aplayer-setting" lrctype="0" list-max-height="400px" fixed="true" volume="0.7" list-folded="true"></meting-js></div></div></div></div></footer><script src="https://cdnjs.loli.net/ajax/libs/moment.js/2.22.2/moment-with-locales.min.js"></script><script>moment.locale("zh-CN")</script><script>var IcarusThemeSettings={site:{url:"https://wxperia.com",external_link:{enable:!0,exclude:[]}},article:{highlight:{clipboard:!0,fold:"unfolded"}}}</script><script src="https://cdnjs.loli.net/ajax/libs/clipboard.js/2.0.4/clipboard.min.js" defer></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/animation.min.js"></script><a id="back-to-top" title="回到顶端" href="javascript:;"><i class="fas fa-chevron-up"></i></a><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/back-to-top.min.js" defer></script><script src="https://cdnjs.loli.net/ajax/libs/lightgallery/1.6.12/js/lightgallery-all.min.js" defer></script><script src="https://cdnjs.loli.net/ajax/libs/justifiedGallery/3.7.0/js/jquery.justifiedGallery.min.js" defer></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/toc.min.js" defer></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/main.min.js" defer></script><script>$.getScript("https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/comment-issue-data.min.js",function(){loadIssueData("52c5fa5cd6ab2aba4c38","c153bf2fcf5d1e3784fcb161c2ca5702ca3bcaee","Wxperia","Wxperia.github.io",!1)})</script><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//css/insight.min.css"><div class="searchbox ins-search"><div class="searchbox-container ins-search-container"><div class="searchbox-input-wrapper"><input class="searchbox-input ins-search-input" type="text" placeholder="想要查找什么..."><span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span></div><div class="searchbox-result-wrapper ins-section-wrapper"><div class="ins-section-container"></div></div></div></div><script>window.INSIGHT_CONFIG={TRANSLATION:{POSTS:"文章",PAGES:"页面",CATEGORIES:"分类",TAGS:"标签",UNTITLED:"(无标题)"},CONTENT_URL:"https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//content.json"}</script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/insight.min.js" defer></script></body></html>